editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::{AGENT_REPLICA_ID, ReplicaId};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  150    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  151    ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  742type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  743
  744#[derive(Default)]
  745struct ScrollbarMarkerState {
  746    scrollbar_size: Size<Pixels>,
  747    dirty: bool,
  748    markers: Arc<[PaintQuad]>,
  749    pending_refresh: Option<Task<Result<()>>>,
  750}
  751
  752impl ScrollbarMarkerState {
  753    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  754        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  755    }
  756}
  757
  758#[derive(Clone, Copy, PartialEq, Eq)]
  759pub enum MinimapVisibility {
  760    Disabled,
  761    Enabled {
  762        /// The configuration currently present in the users settings.
  763        setting_configuration: bool,
  764        /// Whether to override the currently set visibility from the users setting.
  765        toggle_override: bool,
  766    },
  767}
  768
  769impl MinimapVisibility {
  770    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  771        if mode.is_full() {
  772            Self::Enabled {
  773                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  774                toggle_override: false,
  775            }
  776        } else {
  777            Self::Disabled
  778        }
  779    }
  780
  781    fn hidden(&self) -> Self {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => Self::Enabled {
  787                setting_configuration,
  788                toggle_override: setting_configuration,
  789            },
  790            Self::Disabled => Self::Disabled,
  791        }
  792    }
  793
  794    fn disabled(&self) -> bool {
  795        matches!(*self, Self::Disabled)
  796    }
  797
  798    fn settings_visibility(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                ..
  803            } => setting_configuration,
  804            _ => false,
  805        }
  806    }
  807
  808    fn visible(&self) -> bool {
  809        match *self {
  810            Self::Enabled {
  811                setting_configuration,
  812                toggle_override,
  813            } => setting_configuration ^ toggle_override,
  814            _ => false,
  815        }
  816    }
  817
  818    fn toggle_visibility(&self) -> Self {
  819        match *self {
  820            Self::Enabled {
  821                toggle_override,
  822                setting_configuration,
  823            } => Self::Enabled {
  824                setting_configuration,
  825                toggle_override: !toggle_override,
  826            },
  827            Self::Disabled => Self::Disabled,
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  864struct BufferOffset(usize);
  865
  866/// Addons allow storing per-editor state in other crates (e.g. Vim)
  867pub trait Addon: 'static {
  868    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  869
  870    fn render_buffer_header_controls(
  871        &self,
  872        _: &ExcerptInfo,
  873        _: &Window,
  874        _: &App,
  875    ) -> Option<AnyElement> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    collapse_matches: bool,
 1103    autoindent_mode: Option<AutoindentMode>,
 1104    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1105    input_enabled: bool,
 1106    use_modal_editing: bool,
 1107    read_only: bool,
 1108    leader_id: Option<CollaboratorId>,
 1109    remote_id: Option<ViewId>,
 1110    pub hover_state: HoverState,
 1111    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1112    gutter_hovered: bool,
 1113    hovered_link_state: Option<HoveredLinkState>,
 1114    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1115    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1116    active_edit_prediction: Option<EditPredictionState>,
 1117    /// Used to prevent flickering as the user types while the menu is open
 1118    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1119    edit_prediction_settings: EditPredictionSettings,
 1120    edit_predictions_hidden_for_vim_mode: bool,
 1121    show_edit_predictions_override: Option<bool>,
 1122    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1123    edit_prediction_preview: EditPredictionPreview,
 1124    edit_prediction_indent_conflict: bool,
 1125    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1126    inlay_hint_cache: InlayHintCache,
 1127    next_inlay_id: u32,
 1128    next_color_inlay_id: u32,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    serialize_dirty_buffers: bool,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191    selection_drag_state: SelectionDragState,
 1192    colors: Option<LspColorData>,
 1193    refresh_colors_task: Task<()>,
 1194    folding_newlines: Task<()>,
 1195    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1196}
 1197
 1198#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1199enum NextScrollCursorCenterTopBottom {
 1200    #[default]
 1201    Center,
 1202    Top,
 1203    Bottom,
 1204}
 1205
 1206impl NextScrollCursorCenterTopBottom {
 1207    fn next(&self) -> Self {
 1208        match self {
 1209            Self::Center => Self::Top,
 1210            Self::Top => Self::Bottom,
 1211            Self::Bottom => Self::Center,
 1212        }
 1213    }
 1214}
 1215
 1216#[derive(Clone)]
 1217pub struct EditorSnapshot {
 1218    pub mode: EditorMode,
 1219    show_gutter: bool,
 1220    show_line_numbers: Option<bool>,
 1221    show_git_diff_gutter: Option<bool>,
 1222    show_code_actions: Option<bool>,
 1223    show_runnables: Option<bool>,
 1224    show_breakpoints: Option<bool>,
 1225    git_blame_gutter_max_author_length: Option<usize>,
 1226    pub display_snapshot: DisplaySnapshot,
 1227    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1228    is_focused: bool,
 1229    scroll_anchor: ScrollAnchor,
 1230    ongoing_scroll: OngoingScroll,
 1231    current_line_highlight: CurrentLineHighlight,
 1232    gutter_hovered: bool,
 1233}
 1234
 1235#[derive(Default, Debug, Clone, Copy)]
 1236pub struct GutterDimensions {
 1237    pub left_padding: Pixels,
 1238    pub right_padding: Pixels,
 1239    pub width: Pixels,
 1240    pub margin: Pixels,
 1241    pub git_blame_entries_width: Option<Pixels>,
 1242}
 1243
 1244impl GutterDimensions {
 1245    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1246        Self {
 1247            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1248            ..Default::default()
 1249        }
 1250    }
 1251
 1252    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1253        -cx.text_system().descent(font_id, font_size)
 1254    }
 1255    /// The full width of the space taken up by the gutter.
 1256    pub fn full_width(&self) -> Pixels {
 1257        self.margin + self.width
 1258    }
 1259
 1260    /// The width of the space reserved for the fold indicators,
 1261    /// use alongside 'justify_end' and `gutter_width` to
 1262    /// right align content with the line numbers
 1263    pub fn fold_area_width(&self) -> Pixels {
 1264        self.margin + self.right_padding
 1265    }
 1266}
 1267
 1268struct CharacterDimensions {
 1269    em_width: Pixels,
 1270    em_advance: Pixels,
 1271    line_height: Pixels,
 1272}
 1273
 1274#[derive(Debug)]
 1275pub struct RemoteSelection {
 1276    pub replica_id: ReplicaId,
 1277    pub selection: Selection<Anchor>,
 1278    pub cursor_shape: CursorShape,
 1279    pub collaborator_id: CollaboratorId,
 1280    pub line_mode: bool,
 1281    pub user_name: Option<SharedString>,
 1282    pub color: PlayerColor,
 1283}
 1284
 1285#[derive(Clone, Debug)]
 1286struct SelectionHistoryEntry {
 1287    selections: Arc<[Selection<Anchor>]>,
 1288    select_next_state: Option<SelectNextState>,
 1289    select_prev_state: Option<SelectNextState>,
 1290    add_selections_state: Option<AddSelectionsState>,
 1291}
 1292
 1293#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1294enum SelectionHistoryMode {
 1295    Normal,
 1296    Undoing,
 1297    Redoing,
 1298    Skipping,
 1299}
 1300
 1301#[derive(Clone, PartialEq, Eq, Hash)]
 1302struct HoveredCursor {
 1303    replica_id: u16,
 1304    selection_id: usize,
 1305}
 1306
 1307impl Default for SelectionHistoryMode {
 1308    fn default() -> Self {
 1309        Self::Normal
 1310    }
 1311}
 1312
 1313#[derive(Debug)]
 1314/// SelectionEffects controls the side-effects of updating the selection.
 1315///
 1316/// The default behaviour does "what you mostly want":
 1317/// - it pushes to the nav history if the cursor moved by >10 lines
 1318/// - it re-triggers completion requests
 1319/// - it scrolls to fit
 1320///
 1321/// You might want to modify these behaviours. For example when doing a "jump"
 1322/// like go to definition, we always want to add to nav history; but when scrolling
 1323/// in vim mode we never do.
 1324///
 1325/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1326/// move.
 1327#[derive(Clone)]
 1328pub struct SelectionEffects {
 1329    nav_history: Option<bool>,
 1330    completions: bool,
 1331    scroll: Option<Autoscroll>,
 1332}
 1333
 1334impl Default for SelectionEffects {
 1335    fn default() -> Self {
 1336        Self {
 1337            nav_history: None,
 1338            completions: true,
 1339            scroll: Some(Autoscroll::fit()),
 1340        }
 1341    }
 1342}
 1343impl SelectionEffects {
 1344    pub fn scroll(scroll: Autoscroll) -> Self {
 1345        Self {
 1346            scroll: Some(scroll),
 1347            ..Default::default()
 1348        }
 1349    }
 1350
 1351    pub fn no_scroll() -> Self {
 1352        Self {
 1353            scroll: None,
 1354            ..Default::default()
 1355        }
 1356    }
 1357
 1358    pub fn completions(self, completions: bool) -> Self {
 1359        Self {
 1360            completions,
 1361            ..self
 1362        }
 1363    }
 1364
 1365    pub fn nav_history(self, nav_history: bool) -> Self {
 1366        Self {
 1367            nav_history: Some(nav_history),
 1368            ..self
 1369        }
 1370    }
 1371}
 1372
 1373struct DeferredSelectionEffectsState {
 1374    changed: bool,
 1375    effects: SelectionEffects,
 1376    old_cursor_position: Anchor,
 1377    history_entry: SelectionHistoryEntry,
 1378}
 1379
 1380#[derive(Default)]
 1381struct SelectionHistory {
 1382    #[allow(clippy::type_complexity)]
 1383    selections_by_transaction:
 1384        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1385    mode: SelectionHistoryMode,
 1386    undo_stack: VecDeque<SelectionHistoryEntry>,
 1387    redo_stack: VecDeque<SelectionHistoryEntry>,
 1388}
 1389
 1390impl SelectionHistory {
 1391    #[track_caller]
 1392    fn insert_transaction(
 1393        &mut self,
 1394        transaction_id: TransactionId,
 1395        selections: Arc<[Selection<Anchor>]>,
 1396    ) {
 1397        if selections.is_empty() {
 1398            log::error!(
 1399                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1400                std::panic::Location::caller()
 1401            );
 1402            return;
 1403        }
 1404        self.selections_by_transaction
 1405            .insert(transaction_id, (selections, None));
 1406    }
 1407
 1408    #[allow(clippy::type_complexity)]
 1409    fn transaction(
 1410        &self,
 1411        transaction_id: TransactionId,
 1412    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1413        self.selections_by_transaction.get(&transaction_id)
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction_mut(
 1418        &mut self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get_mut(&transaction_id)
 1422    }
 1423
 1424    fn push(&mut self, entry: SelectionHistoryEntry) {
 1425        if !entry.selections.is_empty() {
 1426            match self.mode {
 1427                SelectionHistoryMode::Normal => {
 1428                    self.push_undo(entry);
 1429                    self.redo_stack.clear();
 1430                }
 1431                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1432                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1433                SelectionHistoryMode::Skipping => {}
 1434            }
 1435        }
 1436    }
 1437
 1438    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1439        if self
 1440            .undo_stack
 1441            .back()
 1442            .is_none_or(|e| e.selections != entry.selections)
 1443        {
 1444            self.undo_stack.push_back(entry);
 1445            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1446                self.undo_stack.pop_front();
 1447            }
 1448        }
 1449    }
 1450
 1451    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1452        if self
 1453            .redo_stack
 1454            .back()
 1455            .is_none_or(|e| e.selections != entry.selections)
 1456        {
 1457            self.redo_stack.push_back(entry);
 1458            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1459                self.redo_stack.pop_front();
 1460            }
 1461        }
 1462    }
 1463}
 1464
 1465#[derive(Clone, Copy)]
 1466pub struct RowHighlightOptions {
 1467    pub autoscroll: bool,
 1468    pub include_gutter: bool,
 1469}
 1470
 1471impl Default for RowHighlightOptions {
 1472    fn default() -> Self {
 1473        Self {
 1474            autoscroll: Default::default(),
 1475            include_gutter: true,
 1476        }
 1477    }
 1478}
 1479
 1480struct RowHighlight {
 1481    index: usize,
 1482    range: Range<Anchor>,
 1483    color: Hsla,
 1484    options: RowHighlightOptions,
 1485    type_id: TypeId,
 1486}
 1487
 1488#[derive(Clone, Debug)]
 1489struct AddSelectionsState {
 1490    groups: Vec<AddSelectionsGroup>,
 1491}
 1492
 1493#[derive(Clone, Debug)]
 1494struct AddSelectionsGroup {
 1495    above: bool,
 1496    stack: Vec<usize>,
 1497}
 1498
 1499#[derive(Clone)]
 1500struct SelectNextState {
 1501    query: AhoCorasick,
 1502    wordwise: bool,
 1503    done: bool,
 1504}
 1505
 1506impl std::fmt::Debug for SelectNextState {
 1507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1508        f.debug_struct(std::any::type_name::<Self>())
 1509            .field("wordwise", &self.wordwise)
 1510            .field("done", &self.done)
 1511            .finish()
 1512    }
 1513}
 1514
 1515#[derive(Debug)]
 1516struct AutocloseRegion {
 1517    selection_id: usize,
 1518    range: Range<Anchor>,
 1519    pair: BracketPair,
 1520}
 1521
 1522#[derive(Debug)]
 1523struct SnippetState {
 1524    ranges: Vec<Vec<Range<Anchor>>>,
 1525    active_index: usize,
 1526    choices: Vec<Option<Vec<String>>>,
 1527}
 1528
 1529#[doc(hidden)]
 1530pub struct RenameState {
 1531    pub range: Range<Anchor>,
 1532    pub old_name: Arc<str>,
 1533    pub editor: Entity<Editor>,
 1534    block_id: CustomBlockId,
 1535}
 1536
 1537struct InvalidationStack<T>(Vec<T>);
 1538
 1539struct RegisteredEditPredictionProvider {
 1540    provider: Arc<dyn EditPredictionProviderHandle>,
 1541    _subscription: Subscription,
 1542}
 1543
 1544#[derive(Debug, PartialEq, Eq)]
 1545pub struct ActiveDiagnosticGroup {
 1546    pub active_range: Range<Anchor>,
 1547    pub active_message: String,
 1548    pub group_id: usize,
 1549    pub blocks: HashSet<CustomBlockId>,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553
 1554pub(crate) enum ActiveDiagnostic {
 1555    None,
 1556    All,
 1557    Group(ActiveDiagnosticGroup),
 1558}
 1559
 1560#[derive(Serialize, Deserialize, Clone, Debug)]
 1561pub struct ClipboardSelection {
 1562    /// The number of bytes in this selection.
 1563    pub len: usize,
 1564    /// Whether this was a full-line selection.
 1565    pub is_entire_line: bool,
 1566    /// The indentation of the first line when this content was originally copied.
 1567    pub first_line_indent: u32,
 1568}
 1569
 1570// selections, scroll behavior, was newest selection reversed
 1571type SelectSyntaxNodeHistoryState = (
 1572    Box<[Selection<usize>]>,
 1573    SelectSyntaxNodeScrollBehavior,
 1574    bool,
 1575);
 1576
 1577#[derive(Default)]
 1578struct SelectSyntaxNodeHistory {
 1579    stack: Vec<SelectSyntaxNodeHistoryState>,
 1580    // disable temporarily to allow changing selections without losing the stack
 1581    pub disable_clearing: bool,
 1582}
 1583
 1584impl SelectSyntaxNodeHistory {
 1585    pub fn try_clear(&mut self) {
 1586        if !self.disable_clearing {
 1587            self.stack.clear();
 1588        }
 1589    }
 1590
 1591    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1592        self.stack.push(selection);
 1593    }
 1594
 1595    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1596        self.stack.pop()
 1597    }
 1598}
 1599
 1600enum SelectSyntaxNodeScrollBehavior {
 1601    CursorTop,
 1602    FitSelection,
 1603    CursorBottom,
 1604}
 1605
 1606#[derive(Debug)]
 1607pub(crate) struct NavigationData {
 1608    cursor_anchor: Anchor,
 1609    cursor_position: Point,
 1610    scroll_anchor: ScrollAnchor,
 1611    scroll_top_row: u32,
 1612}
 1613
 1614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1615pub enum GotoDefinitionKind {
 1616    Symbol,
 1617    Declaration,
 1618    Type,
 1619    Implementation,
 1620}
 1621
 1622#[derive(Debug, Clone)]
 1623enum InlayHintRefreshReason {
 1624    ModifiersChanged(bool),
 1625    Toggle(bool),
 1626    SettingsChange(InlayHintSettings),
 1627    NewLinesShown,
 1628    BufferEdited(HashSet<Arc<Language>>),
 1629    RefreshRequested,
 1630    ExcerptsRemoved(Vec<ExcerptId>),
 1631}
 1632
 1633impl InlayHintRefreshReason {
 1634    fn description(&self) -> &'static str {
 1635        match self {
 1636            Self::ModifiersChanged(_) => "modifiers changed",
 1637            Self::Toggle(_) => "toggle",
 1638            Self::SettingsChange(_) => "settings change",
 1639            Self::NewLinesShown => "new lines shown",
 1640            Self::BufferEdited(_) => "buffer edited",
 1641            Self::RefreshRequested => "refresh requested",
 1642            Self::ExcerptsRemoved(_) => "excerpts removed",
 1643        }
 1644    }
 1645}
 1646
 1647pub enum FormatTarget {
 1648    Buffers(HashSet<Entity<Buffer>>),
 1649    Ranges(Vec<Range<MultiBufferPoint>>),
 1650}
 1651
 1652pub(crate) struct FocusedBlock {
 1653    id: BlockId,
 1654    focus_handle: WeakFocusHandle,
 1655}
 1656
 1657#[derive(Clone)]
 1658enum JumpData {
 1659    MultiBufferRow {
 1660        row: MultiBufferRow,
 1661        line_offset_from_top: u32,
 1662    },
 1663    MultiBufferPoint {
 1664        excerpt_id: ExcerptId,
 1665        position: Point,
 1666        anchor: text::Anchor,
 1667        line_offset_from_top: u32,
 1668    },
 1669}
 1670
 1671pub enum MultibufferSelectionMode {
 1672    First,
 1673    All,
 1674}
 1675
 1676#[derive(Clone, Copy, Debug, Default)]
 1677pub struct RewrapOptions {
 1678    pub override_language_settings: bool,
 1679    pub preserve_existing_whitespace: bool,
 1680}
 1681
 1682impl Editor {
 1683    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1687    }
 1688
 1689    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1690        let buffer = cx.new(|cx| Buffer::local("", cx));
 1691        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1692        Self::new(EditorMode::full(), buffer, None, window, cx)
 1693    }
 1694
 1695    pub fn auto_height(
 1696        min_lines: usize,
 1697        max_lines: usize,
 1698        window: &mut Window,
 1699        cx: &mut Context<Self>,
 1700    ) -> Self {
 1701        let buffer = cx.new(|cx| Buffer::local("", cx));
 1702        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1703        Self::new(
 1704            EditorMode::AutoHeight {
 1705                min_lines,
 1706                max_lines: Some(max_lines),
 1707            },
 1708            buffer,
 1709            None,
 1710            window,
 1711            cx,
 1712        )
 1713    }
 1714
 1715    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1716    /// The editor grows as tall as needed to fit its content.
 1717    pub fn auto_height_unbounded(
 1718        min_lines: usize,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| Buffer::local("", cx));
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(
 1725            EditorMode::AutoHeight {
 1726                min_lines,
 1727                max_lines: None,
 1728            },
 1729            buffer,
 1730            None,
 1731            window,
 1732            cx,
 1733        )
 1734    }
 1735
 1736    pub fn for_buffer(
 1737        buffer: Entity<Buffer>,
 1738        project: Option<Entity<Project>>,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1743        Self::new(EditorMode::full(), buffer, project, window, cx)
 1744    }
 1745
 1746    pub fn for_multibuffer(
 1747        buffer: Entity<MultiBuffer>,
 1748        project: Option<Entity<Project>>,
 1749        window: &mut Window,
 1750        cx: &mut Context<Self>,
 1751    ) -> Self {
 1752        Self::new(EditorMode::full(), buffer, project, window, cx)
 1753    }
 1754
 1755    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1756        let mut clone = Self::new(
 1757            self.mode.clone(),
 1758            self.buffer.clone(),
 1759            self.project.clone(),
 1760            window,
 1761            cx,
 1762        );
 1763        self.display_map.update(cx, |display_map, cx| {
 1764            let snapshot = display_map.snapshot(cx);
 1765            clone.display_map.update(cx, |display_map, cx| {
 1766                display_map.set_state(&snapshot, cx);
 1767            });
 1768        });
 1769        clone.folds_did_change(cx);
 1770        clone.selections.clone_state(&self.selections);
 1771        clone.scroll_manager.clone_state(&self.scroll_manager);
 1772        clone.searchable = self.searchable;
 1773        clone.read_only = self.read_only;
 1774        clone
 1775    }
 1776
 1777    pub fn new(
 1778        mode: EditorMode,
 1779        buffer: Entity<MultiBuffer>,
 1780        project: Option<Entity<Project>>,
 1781        window: &mut Window,
 1782        cx: &mut Context<Self>,
 1783    ) -> Self {
 1784        Editor::new_internal(mode, buffer, project, None, window, cx)
 1785    }
 1786
 1787    fn new_internal(
 1788        mode: EditorMode,
 1789        buffer: Entity<MultiBuffer>,
 1790        project: Option<Entity<Project>>,
 1791        display_map: Option<Entity<DisplayMap>>,
 1792        window: &mut Window,
 1793        cx: &mut Context<Self>,
 1794    ) -> Self {
 1795        debug_assert!(
 1796            display_map.is_none() || mode.is_minimap(),
 1797            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1798        );
 1799
 1800        let full_mode = mode.is_full();
 1801        let is_minimap = mode.is_minimap();
 1802        let diagnostics_max_severity = if full_mode {
 1803            EditorSettings::get_global(cx)
 1804                .diagnostics_max_severity
 1805                .unwrap_or(DiagnosticSeverity::Hint)
 1806        } else {
 1807            DiagnosticSeverity::Off
 1808        };
 1809        let style = window.text_style();
 1810        let font_size = style.font_size.to_pixels(window.rem_size());
 1811        let editor = cx.entity().downgrade();
 1812        let fold_placeholder = FoldPlaceholder {
 1813            constrain_width: false,
 1814            render: Arc::new(move |fold_id, fold_range, cx| {
 1815                let editor = editor.clone();
 1816                div()
 1817                    .id(fold_id)
 1818                    .bg(cx.theme().colors().ghost_element_background)
 1819                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1820                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1821                    .rounded_xs()
 1822                    .size_full()
 1823                    .cursor_pointer()
 1824                    .child("")
 1825                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1826                    .on_click(move |_, _window, cx| {
 1827                        editor
 1828                            .update(cx, |editor, cx| {
 1829                                editor.unfold_ranges(
 1830                                    &[fold_range.start..fold_range.end],
 1831                                    true,
 1832                                    false,
 1833                                    cx,
 1834                                );
 1835                                cx.stop_propagation();
 1836                            })
 1837                            .ok();
 1838                    })
 1839                    .into_any()
 1840            }),
 1841            merge_adjacent: true,
 1842            ..FoldPlaceholder::default()
 1843        };
 1844        let display_map = display_map.unwrap_or_else(|| {
 1845            cx.new(|cx| {
 1846                DisplayMap::new(
 1847                    buffer.clone(),
 1848                    style.font(),
 1849                    font_size,
 1850                    None,
 1851                    FILE_HEADER_HEIGHT,
 1852                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1853                    fold_placeholder,
 1854                    diagnostics_max_severity,
 1855                    cx,
 1856                )
 1857            })
 1858        });
 1859
 1860        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1861
 1862        let blink_manager = cx.new(|cx| {
 1863            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1864            if is_minimap {
 1865                blink_manager.disable(cx);
 1866            }
 1867            blink_manager
 1868        });
 1869
 1870        let soft_wrap_mode_override =
 1871            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1872
 1873        let mut project_subscriptions = Vec::new();
 1874        if full_mode && let Some(project) = project.as_ref() {
 1875            project_subscriptions.push(cx.subscribe_in(
 1876                project,
 1877                window,
 1878                |editor, _, event, window, cx| match event {
 1879                    project::Event::RefreshCodeLens => {
 1880                        // we always query lens with actions, without storing them, always refreshing them
 1881                    }
 1882                    project::Event::RefreshInlayHints => {
 1883                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1884                    }
 1885                    project::Event::LanguageServerAdded(..)
 1886                    | project::Event::LanguageServerRemoved(..) => {
 1887                        if editor.tasks_update_task.is_none() {
 1888                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1889                        }
 1890                    }
 1891                    project::Event::SnippetEdit(id, snippet_edits) => {
 1892                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1893                            let focus_handle = editor.focus_handle(cx);
 1894                            if focus_handle.is_focused(window) {
 1895                                let snapshot = buffer.read(cx).snapshot();
 1896                                for (range, snippet) in snippet_edits {
 1897                                    let editor_range =
 1898                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1899                                    editor
 1900                                        .insert_snippet(
 1901                                            &[editor_range],
 1902                                            snippet.clone(),
 1903                                            window,
 1904                                            cx,
 1905                                        )
 1906                                        .ok();
 1907                                }
 1908                            }
 1909                        }
 1910                    }
 1911                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1912                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1913                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1914                        }
 1915                    }
 1916
 1917                    project::Event::EntryRenamed(transaction) => {
 1918                        let Some(workspace) = editor.workspace() else {
 1919                            return;
 1920                        };
 1921                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1922                        else {
 1923                            return;
 1924                        };
 1925                        if active_editor.entity_id() == cx.entity_id() {
 1926                            let edited_buffers_already_open = {
 1927                                let other_editors: Vec<Entity<Editor>> = workspace
 1928                                    .read(cx)
 1929                                    .panes()
 1930                                    .iter()
 1931                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1932                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1933                                    .collect();
 1934
 1935                                transaction.0.keys().all(|buffer| {
 1936                                    other_editors.iter().any(|editor| {
 1937                                        let multi_buffer = editor.read(cx).buffer();
 1938                                        multi_buffer.read(cx).is_singleton()
 1939                                            && multi_buffer.read(cx).as_singleton().map_or(
 1940                                                false,
 1941                                                |singleton| {
 1942                                                    singleton.entity_id() == buffer.entity_id()
 1943                                                },
 1944                                            )
 1945                                    })
 1946                                })
 1947                            };
 1948
 1949                            if !edited_buffers_already_open {
 1950                                let workspace = workspace.downgrade();
 1951                                let transaction = transaction.clone();
 1952                                cx.defer_in(window, move |_, window, cx| {
 1953                                    cx.spawn_in(window, async move |editor, cx| {
 1954                                        Self::open_project_transaction(
 1955                                            &editor,
 1956                                            workspace,
 1957                                            transaction,
 1958                                            "Rename".to_string(),
 1959                                            cx,
 1960                                        )
 1961                                        .await
 1962                                        .ok()
 1963                                    })
 1964                                    .detach();
 1965                                });
 1966                            }
 1967                        }
 1968                    }
 1969
 1970                    _ => {}
 1971                },
 1972            ));
 1973            if let Some(task_inventory) = project
 1974                .read(cx)
 1975                .task_store()
 1976                .read(cx)
 1977                .task_inventory()
 1978                .cloned()
 1979            {
 1980                project_subscriptions.push(cx.observe_in(
 1981                    &task_inventory,
 1982                    window,
 1983                    |editor, _, window, cx| {
 1984                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1985                    },
 1986                ));
 1987            };
 1988
 1989            project_subscriptions.push(cx.subscribe_in(
 1990                &project.read(cx).breakpoint_store(),
 1991                window,
 1992                |editor, _, event, window, cx| match event {
 1993                    BreakpointStoreEvent::ClearDebugLines => {
 1994                        editor.clear_row_highlights::<ActiveDebugLine>();
 1995                        editor.refresh_inline_values(cx);
 1996                    }
 1997                    BreakpointStoreEvent::SetDebugLine => {
 1998                        if editor.go_to_active_debug_line(window, cx) {
 1999                            cx.stop_propagation();
 2000                        }
 2001
 2002                        editor.refresh_inline_values(cx);
 2003                    }
 2004                    _ => {}
 2005                },
 2006            ));
 2007            let git_store = project.read(cx).git_store().clone();
 2008            let project = project.clone();
 2009            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2010                if let GitStoreEvent::RepositoryUpdated(
 2011                    _,
 2012                    RepositoryEvent::Updated {
 2013                        new_instance: true, ..
 2014                    },
 2015                    _,
 2016                ) = event
 2017                {
 2018                    this.load_diff_task = Some(
 2019                        update_uncommitted_diff_for_buffer(
 2020                            cx.entity(),
 2021                            &project,
 2022                            this.buffer.read(cx).all_buffers(),
 2023                            this.buffer.clone(),
 2024                            cx,
 2025                        )
 2026                        .shared(),
 2027                    );
 2028                }
 2029            }));
 2030        }
 2031
 2032        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2033
 2034        let inlay_hint_settings =
 2035            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2036        let focus_handle = cx.focus_handle();
 2037        if !is_minimap {
 2038            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2039                .detach();
 2040            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2041                .detach();
 2042            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2043                .detach();
 2044            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2045                .detach();
 2046            cx.observe_pending_input(window, Self::observe_pending_input)
 2047                .detach();
 2048        }
 2049
 2050        let show_indent_guides =
 2051            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2052                Some(false)
 2053            } else {
 2054                None
 2055            };
 2056
 2057        let breakpoint_store = match (&mode, project.as_ref()) {
 2058            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2059            _ => None,
 2060        };
 2061
 2062        let mut code_action_providers = Vec::new();
 2063        let mut load_uncommitted_diff = None;
 2064        if let Some(project) = project.clone() {
 2065            load_uncommitted_diff = Some(
 2066                update_uncommitted_diff_for_buffer(
 2067                    cx.entity(),
 2068                    &project,
 2069                    buffer.read(cx).all_buffers(),
 2070                    buffer.clone(),
 2071                    cx,
 2072                )
 2073                .shared(),
 2074            );
 2075            code_action_providers.push(Rc::new(project) as Rc<_>);
 2076        }
 2077
 2078        let mut editor = Self {
 2079            focus_handle,
 2080            show_cursor_when_unfocused: false,
 2081            last_focused_descendant: None,
 2082            buffer: buffer.clone(),
 2083            display_map: display_map.clone(),
 2084            placeholder_display_map: None,
 2085            selections,
 2086            scroll_manager: ScrollManager::new(cx),
 2087            columnar_selection_state: None,
 2088            add_selections_state: None,
 2089            select_next_state: None,
 2090            select_prev_state: None,
 2091            selection_history: SelectionHistory::default(),
 2092            defer_selection_effects: false,
 2093            deferred_selection_effects_state: None,
 2094            autoclose_regions: Vec::new(),
 2095            snippet_stack: InvalidationStack::default(),
 2096            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2097            ime_transaction: None,
 2098            active_diagnostics: ActiveDiagnostic::None,
 2099            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2100            inline_diagnostics_update: Task::ready(()),
 2101            inline_diagnostics: Vec::new(),
 2102            soft_wrap_mode_override,
 2103            diagnostics_max_severity,
 2104            hard_wrap: None,
 2105            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2106            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2107            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2108            project,
 2109            blink_manager: blink_manager.clone(),
 2110            show_local_selections: true,
 2111            show_scrollbars: ScrollbarAxes {
 2112                horizontal: full_mode,
 2113                vertical: full_mode,
 2114            },
 2115            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2116            offset_content: !matches!(mode, EditorMode::SingleLine),
 2117            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2118            show_gutter: full_mode,
 2119            show_line_numbers: (!full_mode).then_some(false),
 2120            use_relative_line_numbers: None,
 2121            disable_expand_excerpt_buttons: !full_mode,
 2122            show_git_diff_gutter: None,
 2123            show_code_actions: None,
 2124            show_runnables: None,
 2125            show_breakpoints: None,
 2126            show_wrap_guides: None,
 2127            show_indent_guides,
 2128            highlight_order: 0,
 2129            highlighted_rows: HashMap::default(),
 2130            background_highlights: HashMap::default(),
 2131            gutter_highlights: HashMap::default(),
 2132            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2133            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2134            nav_history: None,
 2135            context_menu: RefCell::new(None),
 2136            context_menu_options: None,
 2137            mouse_context_menu: None,
 2138            completion_tasks: Vec::new(),
 2139            inline_blame_popover: None,
 2140            inline_blame_popover_show_task: None,
 2141            signature_help_state: SignatureHelpState::default(),
 2142            auto_signature_help: None,
 2143            find_all_references_task_sources: Vec::new(),
 2144            next_completion_id: 0,
 2145            next_inlay_id: 0,
 2146            code_action_providers,
 2147            available_code_actions: None,
 2148            code_actions_task: None,
 2149            quick_selection_highlight_task: None,
 2150            debounced_selection_highlight_task: None,
 2151            document_highlights_task: None,
 2152            linked_editing_range_task: None,
 2153            pending_rename: None,
 2154            searchable: !is_minimap,
 2155            cursor_shape: EditorSettings::get_global(cx)
 2156                .cursor_shape
 2157                .unwrap_or_default(),
 2158            current_line_highlight: None,
 2159            autoindent_mode: Some(AutoindentMode::EachLine),
 2160            collapse_matches: false,
 2161            workspace: None,
 2162            input_enabled: !is_minimap,
 2163            use_modal_editing: full_mode,
 2164            read_only: is_minimap,
 2165            use_autoclose: true,
 2166            use_auto_surround: true,
 2167            auto_replace_emoji_shortcode: false,
 2168            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2169            leader_id: None,
 2170            remote_id: None,
 2171            hover_state: HoverState::default(),
 2172            pending_mouse_down: None,
 2173            hovered_link_state: None,
 2174            edit_prediction_provider: None,
 2175            active_edit_prediction: None,
 2176            stale_edit_prediction_in_menu: None,
 2177            edit_prediction_preview: EditPredictionPreview::Inactive {
 2178                released_too_fast: false,
 2179            },
 2180            inline_diagnostics_enabled: full_mode,
 2181            diagnostics_enabled: full_mode,
 2182            word_completions_enabled: full_mode,
 2183            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2184            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2185            gutter_hovered: false,
 2186            pixel_position_of_newest_cursor: None,
 2187            last_bounds: None,
 2188            last_position_map: None,
 2189            expect_bounds_change: None,
 2190            gutter_dimensions: GutterDimensions::default(),
 2191            style: None,
 2192            show_cursor_names: false,
 2193            hovered_cursors: HashMap::default(),
 2194            next_editor_action_id: EditorActionId::default(),
 2195            editor_actions: Rc::default(),
 2196            edit_predictions_hidden_for_vim_mode: false,
 2197            show_edit_predictions_override: None,
 2198            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2199            edit_prediction_settings: EditPredictionSettings::Disabled,
 2200            edit_prediction_indent_conflict: false,
 2201            edit_prediction_requires_modifier_in_indent_conflict: true,
 2202            custom_context_menu: None,
 2203            show_git_blame_gutter: false,
 2204            show_git_blame_inline: false,
 2205            show_selection_menu: None,
 2206            show_git_blame_inline_delay_task: None,
 2207            git_blame_inline_enabled: full_mode
 2208                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2209            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2210            serialize_dirty_buffers: !is_minimap
 2211                && ProjectSettings::get_global(cx)
 2212                    .session
 2213                    .restore_unsaved_buffers,
 2214            blame: None,
 2215            blame_subscription: None,
 2216            tasks: BTreeMap::default(),
 2217
 2218            breakpoint_store,
 2219            gutter_breakpoint_indicator: (None, None),
 2220            hovered_diff_hunk_row: None,
 2221            _subscriptions: (!is_minimap)
 2222                .then(|| {
 2223                    vec![
 2224                        cx.observe(&buffer, Self::on_buffer_changed),
 2225                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2226                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2227                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2228                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2229                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2230                        cx.observe_window_activation(window, |editor, window, cx| {
 2231                            let active = window.is_window_active();
 2232                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2233                                if active {
 2234                                    blink_manager.enable(cx);
 2235                                } else {
 2236                                    blink_manager.disable(cx);
 2237                                }
 2238                            });
 2239                            if active {
 2240                                editor.show_mouse_cursor(cx);
 2241                            }
 2242                        }),
 2243                    ]
 2244                })
 2245                .unwrap_or_default(),
 2246            tasks_update_task: None,
 2247            pull_diagnostics_task: Task::ready(()),
 2248            colors: None,
 2249            refresh_colors_task: Task::ready(()),
 2250            next_color_inlay_id: 0,
 2251            linked_edit_ranges: Default::default(),
 2252            in_project_search: false,
 2253            previous_search_ranges: None,
 2254            breadcrumb_header: None,
 2255            focused_block: None,
 2256            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2257            addons: HashMap::default(),
 2258            registered_buffers: HashMap::default(),
 2259            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2260            selection_mark_mode: false,
 2261            toggle_fold_multiple_buffers: Task::ready(()),
 2262            serialize_selections: Task::ready(()),
 2263            serialize_folds: Task::ready(()),
 2264            text_style_refinement: None,
 2265            load_diff_task: load_uncommitted_diff,
 2266            temporary_diff_override: false,
 2267            mouse_cursor_hidden: false,
 2268            minimap: None,
 2269            hide_mouse_mode: EditorSettings::get_global(cx)
 2270                .hide_mouse
 2271                .unwrap_or_default(),
 2272            change_list: ChangeList::new(),
 2273            mode,
 2274            selection_drag_state: SelectionDragState::None,
 2275            folding_newlines: Task::ready(()),
 2276            lookup_key: None,
 2277        };
 2278
 2279        if is_minimap {
 2280            return editor;
 2281        }
 2282
 2283        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2284            editor
 2285                ._subscriptions
 2286                .push(cx.observe(breakpoints, |_, _, cx| {
 2287                    cx.notify();
 2288                }));
 2289        }
 2290        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2291        editor._subscriptions.extend(project_subscriptions);
 2292
 2293        editor._subscriptions.push(cx.subscribe_in(
 2294            &cx.entity(),
 2295            window,
 2296            |editor, _, e: &EditorEvent, window, cx| match e {
 2297                EditorEvent::ScrollPositionChanged { local, .. } => {
 2298                    if *local {
 2299                        let new_anchor = editor.scroll_manager.anchor();
 2300                        let snapshot = editor.snapshot(window, cx);
 2301                        editor.update_restoration_data(cx, move |data| {
 2302                            data.scroll_position = (
 2303                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2304                                new_anchor.offset,
 2305                            );
 2306                        });
 2307                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2308                        editor.inline_blame_popover.take();
 2309                    }
 2310                }
 2311                EditorEvent::Edited { .. } => {
 2312                    if !vim_enabled(cx) {
 2313                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2314                        let pop_state = editor
 2315                            .change_list
 2316                            .last()
 2317                            .map(|previous| {
 2318                                previous.len() == selections.len()
 2319                                    && previous.iter().enumerate().all(|(ix, p)| {
 2320                                        p.to_display_point(&map).row()
 2321                                            == selections[ix].head().row()
 2322                                    })
 2323                            })
 2324                            .unwrap_or(false);
 2325                        let new_positions = selections
 2326                            .into_iter()
 2327                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2328                            .collect();
 2329                        editor
 2330                            .change_list
 2331                            .push_to_change_list(pop_state, new_positions);
 2332                    }
 2333                }
 2334                _ => (),
 2335            },
 2336        ));
 2337
 2338        if let Some(dap_store) = editor
 2339            .project
 2340            .as_ref()
 2341            .map(|project| project.read(cx).dap_store())
 2342        {
 2343            let weak_editor = cx.weak_entity();
 2344
 2345            editor
 2346                ._subscriptions
 2347                .push(
 2348                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2349                        let session_entity = cx.entity();
 2350                        weak_editor
 2351                            .update(cx, |editor, cx| {
 2352                                editor._subscriptions.push(
 2353                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2354                                );
 2355                            })
 2356                            .ok();
 2357                    }),
 2358                );
 2359
 2360            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2361                editor
 2362                    ._subscriptions
 2363                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2364            }
 2365        }
 2366
 2367        // skip adding the initial selection to selection history
 2368        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2369        editor.end_selection(window, cx);
 2370        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2371
 2372        editor.scroll_manager.show_scrollbars(window, cx);
 2373        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2374
 2375        if full_mode {
 2376            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2377            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2378
 2379            if editor.git_blame_inline_enabled {
 2380                editor.start_git_blame_inline(false, window, cx);
 2381            }
 2382
 2383            editor.go_to_active_debug_line(window, cx);
 2384
 2385            if let Some(buffer) = buffer.read(cx).as_singleton()
 2386                && let Some(project) = editor.project()
 2387            {
 2388                let handle = project.update(cx, |project, cx| {
 2389                    project.register_buffer_with_language_servers(&buffer, cx)
 2390                });
 2391                editor
 2392                    .registered_buffers
 2393                    .insert(buffer.read(cx).remote_id(), handle);
 2394            }
 2395
 2396            editor.minimap =
 2397                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2398            editor.colors = Some(LspColorData::new(cx));
 2399            editor.update_lsp_data(false, None, window, cx);
 2400        }
 2401
 2402        if editor.mode.is_full() {
 2403            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2404        }
 2405
 2406        editor
 2407    }
 2408
 2409    pub fn deploy_mouse_context_menu(
 2410        &mut self,
 2411        position: gpui::Point<Pixels>,
 2412        context_menu: Entity<ContextMenu>,
 2413        window: &mut Window,
 2414        cx: &mut Context<Self>,
 2415    ) {
 2416        self.mouse_context_menu = Some(MouseContextMenu::new(
 2417            self,
 2418            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2419            context_menu,
 2420            window,
 2421            cx,
 2422        ));
 2423    }
 2424
 2425    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2426        self.mouse_context_menu
 2427            .as_ref()
 2428            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2429    }
 2430
 2431    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2432        if self
 2433            .selections
 2434            .pending_anchor()
 2435            .is_some_and(|pending_selection| {
 2436                let snapshot = self.buffer().read(cx).snapshot(cx);
 2437                pending_selection.range().includes(range, &snapshot)
 2438            })
 2439        {
 2440            return true;
 2441        }
 2442
 2443        self.selections
 2444            .disjoint_in_range::<usize>(range.clone(), cx)
 2445            .into_iter()
 2446            .any(|selection| {
 2447                // This is needed to cover a corner case, if we just check for an existing
 2448                // selection in the fold range, having a cursor at the start of the fold
 2449                // marks it as selected. Non-empty selections don't cause this.
 2450                let length = selection.end - selection.start;
 2451                length > 0
 2452            })
 2453    }
 2454
 2455    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2456        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2457    }
 2458
 2459    fn key_context_internal(
 2460        &self,
 2461        has_active_edit_prediction: bool,
 2462        window: &Window,
 2463        cx: &App,
 2464    ) -> KeyContext {
 2465        let mut key_context = KeyContext::new_with_defaults();
 2466        key_context.add("Editor");
 2467        let mode = match self.mode {
 2468            EditorMode::SingleLine => "single_line",
 2469            EditorMode::AutoHeight { .. } => "auto_height",
 2470            EditorMode::Minimap { .. } => "minimap",
 2471            EditorMode::Full { .. } => "full",
 2472        };
 2473
 2474        if EditorSettings::jupyter_enabled(cx) {
 2475            key_context.add("jupyter");
 2476        }
 2477
 2478        key_context.set("mode", mode);
 2479        if self.pending_rename.is_some() {
 2480            key_context.add("renaming");
 2481        }
 2482
 2483        match self.context_menu.borrow().as_ref() {
 2484            Some(CodeContextMenu::Completions(menu)) => {
 2485                if menu.visible() {
 2486                    key_context.add("menu");
 2487                    key_context.add("showing_completions");
 2488                }
 2489            }
 2490            Some(CodeContextMenu::CodeActions(menu)) => {
 2491                if menu.visible() {
 2492                    key_context.add("menu");
 2493                    key_context.add("showing_code_actions")
 2494                }
 2495            }
 2496            None => {}
 2497        }
 2498
 2499        if self.signature_help_state.has_multiple_signatures() {
 2500            key_context.add("showing_signature_help");
 2501        }
 2502
 2503        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2504        if !self.focus_handle(cx).contains_focused(window, cx)
 2505            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2506        {
 2507            for addon in self.addons.values() {
 2508                addon.extend_key_context(&mut key_context, cx)
 2509            }
 2510        }
 2511
 2512        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2513            if let Some(extension) = singleton_buffer
 2514                .read(cx)
 2515                .file()
 2516                .and_then(|file| file.path().extension())
 2517            {
 2518                key_context.set("extension", extension.to_string());
 2519            }
 2520        } else {
 2521            key_context.add("multibuffer");
 2522        }
 2523
 2524        if has_active_edit_prediction {
 2525            if self.edit_prediction_in_conflict() {
 2526                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2527            } else {
 2528                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2529                key_context.add("copilot_suggestion");
 2530            }
 2531        }
 2532
 2533        if self.selection_mark_mode {
 2534            key_context.add("selection_mode");
 2535        }
 2536
 2537        key_context
 2538    }
 2539
 2540    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2541        self.last_bounds.as_ref()
 2542    }
 2543
 2544    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2545        if self.mouse_cursor_hidden {
 2546            self.mouse_cursor_hidden = false;
 2547            cx.notify();
 2548        }
 2549    }
 2550
 2551    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2552        let hide_mouse_cursor = match origin {
 2553            HideMouseCursorOrigin::TypingAction => {
 2554                matches!(
 2555                    self.hide_mouse_mode,
 2556                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2557                )
 2558            }
 2559            HideMouseCursorOrigin::MovementAction => {
 2560                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2561            }
 2562        };
 2563        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2564            self.mouse_cursor_hidden = hide_mouse_cursor;
 2565            cx.notify();
 2566        }
 2567    }
 2568
 2569    pub fn edit_prediction_in_conflict(&self) -> bool {
 2570        if !self.show_edit_predictions_in_menu() {
 2571            return false;
 2572        }
 2573
 2574        let showing_completions = self
 2575            .context_menu
 2576            .borrow()
 2577            .as_ref()
 2578            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2579
 2580        showing_completions
 2581            || self.edit_prediction_requires_modifier()
 2582            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2583            // bindings to insert tab characters.
 2584            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2585    }
 2586
 2587    pub fn accept_edit_prediction_keybind(
 2588        &self,
 2589        accept_partial: bool,
 2590        window: &Window,
 2591        cx: &App,
 2592    ) -> AcceptEditPredictionBinding {
 2593        let key_context = self.key_context_internal(true, window, cx);
 2594        let in_conflict = self.edit_prediction_in_conflict();
 2595
 2596        let bindings = if accept_partial {
 2597            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2598        } else {
 2599            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2600        };
 2601
 2602        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2603        // just the first one.
 2604        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2605            !in_conflict
 2606                || binding
 2607                    .keystrokes()
 2608                    .first()
 2609                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2610        }))
 2611    }
 2612
 2613    pub fn new_file(
 2614        workspace: &mut Workspace,
 2615        _: &workspace::NewFile,
 2616        window: &mut Window,
 2617        cx: &mut Context<Workspace>,
 2618    ) {
 2619        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2620            "Failed to create buffer",
 2621            window,
 2622            cx,
 2623            |e, _, _| match e.error_code() {
 2624                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2625                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2626                e.error_tag("required").unwrap_or("the latest version")
 2627            )),
 2628                _ => None,
 2629            },
 2630        );
 2631    }
 2632
 2633    pub fn new_in_workspace(
 2634        workspace: &mut Workspace,
 2635        window: &mut Window,
 2636        cx: &mut Context<Workspace>,
 2637    ) -> Task<Result<Entity<Editor>>> {
 2638        let project = workspace.project().clone();
 2639        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2640
 2641        cx.spawn_in(window, async move |workspace, cx| {
 2642            let buffer = create.await?;
 2643            workspace.update_in(cx, |workspace, window, cx| {
 2644                let editor =
 2645                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2646                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2647                editor
 2648            })
 2649        })
 2650    }
 2651
 2652    fn new_file_vertical(
 2653        workspace: &mut Workspace,
 2654        _: &workspace::NewFileSplitVertical,
 2655        window: &mut Window,
 2656        cx: &mut Context<Workspace>,
 2657    ) {
 2658        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2659    }
 2660
 2661    fn new_file_horizontal(
 2662        workspace: &mut Workspace,
 2663        _: &workspace::NewFileSplitHorizontal,
 2664        window: &mut Window,
 2665        cx: &mut Context<Workspace>,
 2666    ) {
 2667        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2668    }
 2669
 2670    fn new_file_in_direction(
 2671        workspace: &mut Workspace,
 2672        direction: SplitDirection,
 2673        window: &mut Window,
 2674        cx: &mut Context<Workspace>,
 2675    ) {
 2676        let project = workspace.project().clone();
 2677        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2678
 2679        cx.spawn_in(window, async move |workspace, cx| {
 2680            let buffer = create.await?;
 2681            workspace.update_in(cx, move |workspace, window, cx| {
 2682                workspace.split_item(
 2683                    direction,
 2684                    Box::new(
 2685                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2686                    ),
 2687                    window,
 2688                    cx,
 2689                )
 2690            })?;
 2691            anyhow::Ok(())
 2692        })
 2693        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2694            match e.error_code() {
 2695                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2696                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2697                e.error_tag("required").unwrap_or("the latest version")
 2698            )),
 2699                _ => None,
 2700            }
 2701        });
 2702    }
 2703
 2704    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2705        self.leader_id
 2706    }
 2707
 2708    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2709        &self.buffer
 2710    }
 2711
 2712    pub fn project(&self) -> Option<&Entity<Project>> {
 2713        self.project.as_ref()
 2714    }
 2715
 2716    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2717        self.workspace.as_ref()?.0.upgrade()
 2718    }
 2719
 2720    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2721        self.buffer().read(cx).title(cx)
 2722    }
 2723
 2724    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2725        let git_blame_gutter_max_author_length = self
 2726            .render_git_blame_gutter(cx)
 2727            .then(|| {
 2728                if let Some(blame) = self.blame.as_ref() {
 2729                    let max_author_length =
 2730                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2731                    Some(max_author_length)
 2732                } else {
 2733                    None
 2734                }
 2735            })
 2736            .flatten();
 2737
 2738        EditorSnapshot {
 2739            mode: self.mode.clone(),
 2740            show_gutter: self.show_gutter,
 2741            show_line_numbers: self.show_line_numbers,
 2742            show_git_diff_gutter: self.show_git_diff_gutter,
 2743            show_code_actions: self.show_code_actions,
 2744            show_runnables: self.show_runnables,
 2745            show_breakpoints: self.show_breakpoints,
 2746            git_blame_gutter_max_author_length,
 2747            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2748            placeholder_display_snapshot: self
 2749                .placeholder_display_map
 2750                .as_ref()
 2751                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2752            scroll_anchor: self.scroll_manager.anchor(),
 2753            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2754            is_focused: self.focus_handle.is_focused(window),
 2755            current_line_highlight: self
 2756                .current_line_highlight
 2757                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2758            gutter_hovered: self.gutter_hovered,
 2759        }
 2760    }
 2761
 2762    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2763        self.buffer.read(cx).language_at(point, cx)
 2764    }
 2765
 2766    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2767        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2768    }
 2769
 2770    pub fn active_excerpt(
 2771        &self,
 2772        cx: &App,
 2773    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2774        self.buffer
 2775            .read(cx)
 2776            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2777    }
 2778
 2779    pub fn mode(&self) -> &EditorMode {
 2780        &self.mode
 2781    }
 2782
 2783    pub fn set_mode(&mut self, mode: EditorMode) {
 2784        self.mode = mode;
 2785    }
 2786
 2787    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2788        self.collaboration_hub.as_deref()
 2789    }
 2790
 2791    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2792        self.collaboration_hub = Some(hub);
 2793    }
 2794
 2795    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2796        self.in_project_search = in_project_search;
 2797    }
 2798
 2799    pub fn set_custom_context_menu(
 2800        &mut self,
 2801        f: impl 'static
 2802        + Fn(
 2803            &mut Self,
 2804            DisplayPoint,
 2805            &mut Window,
 2806            &mut Context<Self>,
 2807        ) -> Option<Entity<ui::ContextMenu>>,
 2808    ) {
 2809        self.custom_context_menu = Some(Box::new(f))
 2810    }
 2811
 2812    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2813        self.completion_provider = provider;
 2814    }
 2815
 2816    #[cfg(any(test, feature = "test-support"))]
 2817    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2818        self.completion_provider.clone()
 2819    }
 2820
 2821    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2822        self.semantics_provider.clone()
 2823    }
 2824
 2825    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2826        self.semantics_provider = provider;
 2827    }
 2828
 2829    pub fn set_edit_prediction_provider<T>(
 2830        &mut self,
 2831        provider: Option<Entity<T>>,
 2832        window: &mut Window,
 2833        cx: &mut Context<Self>,
 2834    ) where
 2835        T: EditPredictionProvider,
 2836    {
 2837        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2838            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2839                if this.focus_handle.is_focused(window) {
 2840                    this.update_visible_edit_prediction(window, cx);
 2841                }
 2842            }),
 2843            provider: Arc::new(provider),
 2844        });
 2845        self.update_edit_prediction_settings(cx);
 2846        self.refresh_edit_prediction(false, false, window, cx);
 2847    }
 2848
 2849    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2850        self.placeholder_display_map
 2851            .as_ref()
 2852            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2853    }
 2854
 2855    pub fn set_placeholder_text(
 2856        &mut self,
 2857        placeholder_text: &str,
 2858        window: &mut Window,
 2859        cx: &mut Context<Self>,
 2860    ) {
 2861        let multibuffer = cx
 2862            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2863
 2864        let style = window.text_style();
 2865
 2866        self.placeholder_display_map = Some(cx.new(|cx| {
 2867            DisplayMap::new(
 2868                multibuffer,
 2869                style.font(),
 2870                style.font_size.to_pixels(window.rem_size()),
 2871                None,
 2872                FILE_HEADER_HEIGHT,
 2873                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2874                Default::default(),
 2875                DiagnosticSeverity::Off,
 2876                cx,
 2877            )
 2878        }));
 2879        cx.notify();
 2880    }
 2881
 2882    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2883        self.cursor_shape = cursor_shape;
 2884
 2885        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2886        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2887
 2888        cx.notify();
 2889    }
 2890
 2891    pub fn set_current_line_highlight(
 2892        &mut self,
 2893        current_line_highlight: Option<CurrentLineHighlight>,
 2894    ) {
 2895        self.current_line_highlight = current_line_highlight;
 2896    }
 2897
 2898    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2899        self.collapse_matches = collapse_matches;
 2900    }
 2901
 2902    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2903        let buffers = self.buffer.read(cx).all_buffers();
 2904        let Some(project) = self.project.as_ref() else {
 2905            return;
 2906        };
 2907        project.update(cx, |project, cx| {
 2908            for buffer in buffers {
 2909                self.registered_buffers
 2910                    .entry(buffer.read(cx).remote_id())
 2911                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2912            }
 2913        })
 2914    }
 2915
 2916    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2917        if self.collapse_matches {
 2918            return range.start..range.start;
 2919        }
 2920        range.clone()
 2921    }
 2922
 2923    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2924        if self.display_map.read(cx).clip_at_line_ends != clip {
 2925            self.display_map
 2926                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2927        }
 2928    }
 2929
 2930    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2931        self.input_enabled = input_enabled;
 2932    }
 2933
 2934    pub fn set_edit_predictions_hidden_for_vim_mode(
 2935        &mut self,
 2936        hidden: bool,
 2937        window: &mut Window,
 2938        cx: &mut Context<Self>,
 2939    ) {
 2940        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2941            self.edit_predictions_hidden_for_vim_mode = hidden;
 2942            if hidden {
 2943                self.update_visible_edit_prediction(window, cx);
 2944            } else {
 2945                self.refresh_edit_prediction(true, false, window, cx);
 2946            }
 2947        }
 2948    }
 2949
 2950    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2951        self.menu_edit_predictions_policy = value;
 2952    }
 2953
 2954    pub fn set_autoindent(&mut self, autoindent: bool) {
 2955        if autoindent {
 2956            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2957        } else {
 2958            self.autoindent_mode = None;
 2959        }
 2960    }
 2961
 2962    pub fn read_only(&self, cx: &App) -> bool {
 2963        self.read_only || self.buffer.read(cx).read_only()
 2964    }
 2965
 2966    pub fn set_read_only(&mut self, read_only: bool) {
 2967        self.read_only = read_only;
 2968    }
 2969
 2970    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2971        self.use_autoclose = autoclose;
 2972    }
 2973
 2974    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2975        self.use_auto_surround = auto_surround;
 2976    }
 2977
 2978    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2979        self.auto_replace_emoji_shortcode = auto_replace;
 2980    }
 2981
 2982    pub fn toggle_edit_predictions(
 2983        &mut self,
 2984        _: &ToggleEditPrediction,
 2985        window: &mut Window,
 2986        cx: &mut Context<Self>,
 2987    ) {
 2988        if self.show_edit_predictions_override.is_some() {
 2989            self.set_show_edit_predictions(None, window, cx);
 2990        } else {
 2991            let show_edit_predictions = !self.edit_predictions_enabled();
 2992            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2993        }
 2994    }
 2995
 2996    pub fn set_show_edit_predictions(
 2997        &mut self,
 2998        show_edit_predictions: Option<bool>,
 2999        window: &mut Window,
 3000        cx: &mut Context<Self>,
 3001    ) {
 3002        self.show_edit_predictions_override = show_edit_predictions;
 3003        self.update_edit_prediction_settings(cx);
 3004
 3005        if let Some(false) = show_edit_predictions {
 3006            self.discard_edit_prediction(false, cx);
 3007        } else {
 3008            self.refresh_edit_prediction(false, true, window, cx);
 3009        }
 3010    }
 3011
 3012    fn edit_predictions_disabled_in_scope(
 3013        &self,
 3014        buffer: &Entity<Buffer>,
 3015        buffer_position: language::Anchor,
 3016        cx: &App,
 3017    ) -> bool {
 3018        let snapshot = buffer.read(cx).snapshot();
 3019        let settings = snapshot.settings_at(buffer_position, cx);
 3020
 3021        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3022            return false;
 3023        };
 3024
 3025        scope.override_name().is_some_and(|scope_name| {
 3026            settings
 3027                .edit_predictions_disabled_in
 3028                .iter()
 3029                .any(|s| s == scope_name)
 3030        })
 3031    }
 3032
 3033    pub fn set_use_modal_editing(&mut self, to: bool) {
 3034        self.use_modal_editing = to;
 3035    }
 3036
 3037    pub fn use_modal_editing(&self) -> bool {
 3038        self.use_modal_editing
 3039    }
 3040
 3041    fn selections_did_change(
 3042        &mut self,
 3043        local: bool,
 3044        old_cursor_position: &Anchor,
 3045        effects: SelectionEffects,
 3046        window: &mut Window,
 3047        cx: &mut Context<Self>,
 3048    ) {
 3049        window.invalidate_character_coordinates();
 3050
 3051        // Copy selections to primary selection buffer
 3052        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3053        if local {
 3054            let selections = self.selections.all::<usize>(cx);
 3055            let buffer_handle = self.buffer.read(cx).read(cx);
 3056
 3057            let mut text = String::new();
 3058            for (index, selection) in selections.iter().enumerate() {
 3059                let text_for_selection = buffer_handle
 3060                    .text_for_range(selection.start..selection.end)
 3061                    .collect::<String>();
 3062
 3063                text.push_str(&text_for_selection);
 3064                if index != selections.len() - 1 {
 3065                    text.push('\n');
 3066                }
 3067            }
 3068
 3069            if !text.is_empty() {
 3070                cx.write_to_primary(ClipboardItem::new_string(text));
 3071            }
 3072        }
 3073
 3074        let selection_anchors = self.selections.disjoint_anchors_arc();
 3075
 3076        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3077            self.buffer.update(cx, |buffer, cx| {
 3078                buffer.set_active_selections(
 3079                    &selection_anchors,
 3080                    self.selections.line_mode(),
 3081                    self.cursor_shape,
 3082                    cx,
 3083                )
 3084            });
 3085        }
 3086        let display_map = self
 3087            .display_map
 3088            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3089        let buffer = display_map.buffer_snapshot();
 3090        if self.selections.count() == 1 {
 3091            self.add_selections_state = None;
 3092        }
 3093        self.select_next_state = None;
 3094        self.select_prev_state = None;
 3095        self.select_syntax_node_history.try_clear();
 3096        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3097        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3098        self.take_rename(false, window, cx);
 3099
 3100        let newest_selection = self.selections.newest_anchor();
 3101        let new_cursor_position = newest_selection.head();
 3102        let selection_start = newest_selection.start;
 3103
 3104        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3105            self.push_to_nav_history(
 3106                *old_cursor_position,
 3107                Some(new_cursor_position.to_point(buffer)),
 3108                false,
 3109                effects.nav_history == Some(true),
 3110                cx,
 3111            );
 3112        }
 3113
 3114        if local {
 3115            if let Some(buffer_id) = new_cursor_position.buffer_id
 3116                && !self.registered_buffers.contains_key(&buffer_id)
 3117                && let Some(project) = self.project.as_ref()
 3118            {
 3119                project.update(cx, |project, cx| {
 3120                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3121                        return;
 3122                    };
 3123                    self.registered_buffers.insert(
 3124                        buffer_id,
 3125                        project.register_buffer_with_language_servers(&buffer, cx),
 3126                    );
 3127                })
 3128            }
 3129
 3130            let mut context_menu = self.context_menu.borrow_mut();
 3131            let completion_menu = match context_menu.as_ref() {
 3132                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3133                Some(CodeContextMenu::CodeActions(_)) => {
 3134                    *context_menu = None;
 3135                    None
 3136                }
 3137                None => None,
 3138            };
 3139            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3140            drop(context_menu);
 3141
 3142            if effects.completions
 3143                && let Some(completion_position) = completion_position
 3144            {
 3145                let start_offset = selection_start.to_offset(buffer);
 3146                let position_matches = start_offset == completion_position.to_offset(buffer);
 3147                let continue_showing = if position_matches {
 3148                    if self.snippet_stack.is_empty() {
 3149                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3150                            == Some(CharKind::Word)
 3151                    } else {
 3152                        // Snippet choices can be shown even when the cursor is in whitespace.
 3153                        // Dismissing the menu with actions like backspace is handled by
 3154                        // invalidation regions.
 3155                        true
 3156                    }
 3157                } else {
 3158                    false
 3159                };
 3160
 3161                if continue_showing {
 3162                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3163                } else {
 3164                    self.hide_context_menu(window, cx);
 3165                }
 3166            }
 3167
 3168            hide_hover(self, cx);
 3169
 3170            if old_cursor_position.to_display_point(&display_map).row()
 3171                != new_cursor_position.to_display_point(&display_map).row()
 3172            {
 3173                self.available_code_actions.take();
 3174            }
 3175            self.refresh_code_actions(window, cx);
 3176            self.refresh_document_highlights(cx);
 3177            self.refresh_selected_text_highlights(false, window, cx);
 3178            refresh_matching_bracket_highlights(self, cx);
 3179            self.update_visible_edit_prediction(window, cx);
 3180            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3181            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3182            self.inline_blame_popover.take();
 3183            if self.git_blame_inline_enabled {
 3184                self.start_inline_blame_timer(window, cx);
 3185            }
 3186        }
 3187
 3188        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3189        cx.emit(EditorEvent::SelectionsChanged { local });
 3190
 3191        let selections = &self.selections.disjoint_anchors_arc();
 3192        if selections.len() == 1 {
 3193            cx.emit(SearchEvent::ActiveMatchChanged)
 3194        }
 3195        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3196            let inmemory_selections = selections
 3197                .iter()
 3198                .map(|s| {
 3199                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3200                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3201                })
 3202                .collect();
 3203            self.update_restoration_data(cx, |data| {
 3204                data.selections = inmemory_selections;
 3205            });
 3206
 3207            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3208                && let Some(workspace_id) =
 3209                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3210            {
 3211                let snapshot = self.buffer().read(cx).snapshot(cx);
 3212                let selections = selections.clone();
 3213                let background_executor = cx.background_executor().clone();
 3214                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3215                self.serialize_selections = cx.background_spawn(async move {
 3216                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3217                    let db_selections = selections
 3218                        .iter()
 3219                        .map(|selection| {
 3220                            (
 3221                                selection.start.to_offset(&snapshot),
 3222                                selection.end.to_offset(&snapshot),
 3223                            )
 3224                        })
 3225                        .collect();
 3226
 3227                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3228                        .await
 3229                        .with_context(|| {
 3230                            format!(
 3231                                "persisting editor selections for editor {editor_id}, \
 3232                                workspace {workspace_id:?}"
 3233                            )
 3234                        })
 3235                        .log_err();
 3236                });
 3237            }
 3238        }
 3239
 3240        cx.notify();
 3241    }
 3242
 3243    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3244        use text::ToOffset as _;
 3245        use text::ToPoint as _;
 3246
 3247        if self.mode.is_minimap()
 3248            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3249        {
 3250            return;
 3251        }
 3252
 3253        if !self.buffer().read(cx).is_singleton() {
 3254            return;
 3255        }
 3256
 3257        let display_snapshot = self
 3258            .display_map
 3259            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3260        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3261            return;
 3262        };
 3263        let inmemory_folds = display_snapshot
 3264            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3265            .map(|fold| {
 3266                fold.range.start.text_anchor.to_point(&snapshot)
 3267                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3268            })
 3269            .collect();
 3270        self.update_restoration_data(cx, |data| {
 3271            data.folds = inmemory_folds;
 3272        });
 3273
 3274        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3275            return;
 3276        };
 3277        let background_executor = cx.background_executor().clone();
 3278        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3279        let db_folds = display_snapshot
 3280            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3281            .map(|fold| {
 3282                (
 3283                    fold.range.start.text_anchor.to_offset(&snapshot),
 3284                    fold.range.end.text_anchor.to_offset(&snapshot),
 3285                )
 3286            })
 3287            .collect();
 3288        self.serialize_folds = cx.background_spawn(async move {
 3289            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3290            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3291                .await
 3292                .with_context(|| {
 3293                    format!(
 3294                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3295                    )
 3296                })
 3297                .log_err();
 3298        });
 3299    }
 3300
 3301    pub fn sync_selections(
 3302        &mut self,
 3303        other: Entity<Editor>,
 3304        cx: &mut Context<Self>,
 3305    ) -> gpui::Subscription {
 3306        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3307        if !other_selections.is_empty() {
 3308            self.selections.change_with(cx, |selections| {
 3309                selections.select_anchors(other_selections);
 3310            });
 3311        }
 3312
 3313        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3314            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3315                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3316                if other_selections.is_empty() {
 3317                    return;
 3318                }
 3319                this.selections.change_with(cx, |selections| {
 3320                    selections.select_anchors(other_selections);
 3321                });
 3322            }
 3323        });
 3324
 3325        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3326            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3327                let these_selections = this.selections.disjoint_anchors().to_vec();
 3328                if these_selections.is_empty() {
 3329                    return;
 3330                }
 3331                other.update(cx, |other_editor, cx| {
 3332                    other_editor.selections.change_with(cx, |selections| {
 3333                        selections.select_anchors(these_selections);
 3334                    })
 3335                });
 3336            }
 3337        });
 3338
 3339        Subscription::join(other_subscription, this_subscription)
 3340    }
 3341
 3342    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3343    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3344    /// effects of selection change occur at the end of the transaction.
 3345    pub fn change_selections<R>(
 3346        &mut self,
 3347        effects: SelectionEffects,
 3348        window: &mut Window,
 3349        cx: &mut Context<Self>,
 3350        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3351    ) -> R {
 3352        if let Some(state) = &mut self.deferred_selection_effects_state {
 3353            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3354            state.effects.completions = effects.completions;
 3355            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3356            let (changed, result) = self.selections.change_with(cx, change);
 3357            state.changed |= changed;
 3358            return result;
 3359        }
 3360        let mut state = DeferredSelectionEffectsState {
 3361            changed: false,
 3362            effects,
 3363            old_cursor_position: self.selections.newest_anchor().head(),
 3364            history_entry: SelectionHistoryEntry {
 3365                selections: self.selections.disjoint_anchors_arc(),
 3366                select_next_state: self.select_next_state.clone(),
 3367                select_prev_state: self.select_prev_state.clone(),
 3368                add_selections_state: self.add_selections_state.clone(),
 3369            },
 3370        };
 3371        let (changed, result) = self.selections.change_with(cx, change);
 3372        state.changed = state.changed || changed;
 3373        if self.defer_selection_effects {
 3374            self.deferred_selection_effects_state = Some(state);
 3375        } else {
 3376            self.apply_selection_effects(state, window, cx);
 3377        }
 3378        result
 3379    }
 3380
 3381    /// Defers the effects of selection change, so that the effects of multiple calls to
 3382    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3383    /// to selection history and the state of popovers based on selection position aren't
 3384    /// erroneously updated.
 3385    pub fn with_selection_effects_deferred<R>(
 3386        &mut self,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3390    ) -> R {
 3391        let already_deferred = self.defer_selection_effects;
 3392        self.defer_selection_effects = true;
 3393        let result = update(self, window, cx);
 3394        if !already_deferred {
 3395            self.defer_selection_effects = false;
 3396            if let Some(state) = self.deferred_selection_effects_state.take() {
 3397                self.apply_selection_effects(state, window, cx);
 3398            }
 3399        }
 3400        result
 3401    }
 3402
 3403    fn apply_selection_effects(
 3404        &mut self,
 3405        state: DeferredSelectionEffectsState,
 3406        window: &mut Window,
 3407        cx: &mut Context<Self>,
 3408    ) {
 3409        if state.changed {
 3410            self.selection_history.push(state.history_entry);
 3411
 3412            if let Some(autoscroll) = state.effects.scroll {
 3413                self.request_autoscroll(autoscroll, cx);
 3414            }
 3415
 3416            let old_cursor_position = &state.old_cursor_position;
 3417
 3418            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3419
 3420            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3421                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3422            }
 3423        }
 3424    }
 3425
 3426    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3427    where
 3428        I: IntoIterator<Item = (Range<S>, T)>,
 3429        S: ToOffset,
 3430        T: Into<Arc<str>>,
 3431    {
 3432        if self.read_only(cx) {
 3433            return;
 3434        }
 3435
 3436        self.buffer
 3437            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3438    }
 3439
 3440    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3441    where
 3442        I: IntoIterator<Item = (Range<S>, T)>,
 3443        S: ToOffset,
 3444        T: Into<Arc<str>>,
 3445    {
 3446        if self.read_only(cx) {
 3447            return;
 3448        }
 3449
 3450        self.buffer.update(cx, |buffer, cx| {
 3451            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3452        });
 3453    }
 3454
 3455    pub fn edit_with_block_indent<I, S, T>(
 3456        &mut self,
 3457        edits: I,
 3458        original_indent_columns: Vec<Option<u32>>,
 3459        cx: &mut Context<Self>,
 3460    ) where
 3461        I: IntoIterator<Item = (Range<S>, T)>,
 3462        S: ToOffset,
 3463        T: Into<Arc<str>>,
 3464    {
 3465        if self.read_only(cx) {
 3466            return;
 3467        }
 3468
 3469        self.buffer.update(cx, |buffer, cx| {
 3470            buffer.edit(
 3471                edits,
 3472                Some(AutoindentMode::Block {
 3473                    original_indent_columns,
 3474                }),
 3475                cx,
 3476            )
 3477        });
 3478    }
 3479
 3480    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3481        self.hide_context_menu(window, cx);
 3482
 3483        match phase {
 3484            SelectPhase::Begin {
 3485                position,
 3486                add,
 3487                click_count,
 3488            } => self.begin_selection(position, add, click_count, window, cx),
 3489            SelectPhase::BeginColumnar {
 3490                position,
 3491                goal_column,
 3492                reset,
 3493                mode,
 3494            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3495            SelectPhase::Extend {
 3496                position,
 3497                click_count,
 3498            } => self.extend_selection(position, click_count, window, cx),
 3499            SelectPhase::Update {
 3500                position,
 3501                goal_column,
 3502                scroll_delta,
 3503            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3504            SelectPhase::End => self.end_selection(window, cx),
 3505        }
 3506    }
 3507
 3508    fn extend_selection(
 3509        &mut self,
 3510        position: DisplayPoint,
 3511        click_count: usize,
 3512        window: &mut Window,
 3513        cx: &mut Context<Self>,
 3514    ) {
 3515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3516        let tail = self.selections.newest::<usize>(cx).tail();
 3517        let click_count = click_count.max(match self.selections.select_mode() {
 3518            SelectMode::Character => 1,
 3519            SelectMode::Word(_) => 2,
 3520            SelectMode::Line(_) => 3,
 3521            SelectMode::All => 4,
 3522        });
 3523        self.begin_selection(position, false, click_count, window, cx);
 3524
 3525        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3526
 3527        let current_selection = match self.selections.select_mode() {
 3528            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3529            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3530        };
 3531
 3532        let mut pending_selection = self
 3533            .selections
 3534            .pending_anchor()
 3535            .cloned()
 3536            .expect("extend_selection not called with pending selection");
 3537
 3538        if pending_selection
 3539            .start
 3540            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3541            == Ordering::Greater
 3542        {
 3543            pending_selection.start = current_selection.start;
 3544        }
 3545        if pending_selection
 3546            .end
 3547            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3548            == Ordering::Less
 3549        {
 3550            pending_selection.end = current_selection.end;
 3551            pending_selection.reversed = true;
 3552        }
 3553
 3554        let mut pending_mode = self.selections.pending_mode().unwrap();
 3555        match &mut pending_mode {
 3556            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3557            _ => {}
 3558        }
 3559
 3560        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3561            SelectionEffects::scroll(Autoscroll::fit())
 3562        } else {
 3563            SelectionEffects::no_scroll()
 3564        };
 3565
 3566        self.change_selections(effects, window, cx, |s| {
 3567            s.set_pending(pending_selection.clone(), pending_mode);
 3568            s.set_is_extending(true);
 3569        });
 3570    }
 3571
 3572    fn begin_selection(
 3573        &mut self,
 3574        position: DisplayPoint,
 3575        add: bool,
 3576        click_count: usize,
 3577        window: &mut Window,
 3578        cx: &mut Context<Self>,
 3579    ) {
 3580        if !self.focus_handle.is_focused(window) {
 3581            self.last_focused_descendant = None;
 3582            window.focus(&self.focus_handle);
 3583        }
 3584
 3585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3586        let buffer = display_map.buffer_snapshot();
 3587        let position = display_map.clip_point(position, Bias::Left);
 3588
 3589        let start;
 3590        let end;
 3591        let mode;
 3592        let mut auto_scroll;
 3593        match click_count {
 3594            1 => {
 3595                start = buffer.anchor_before(position.to_point(&display_map));
 3596                end = start;
 3597                mode = SelectMode::Character;
 3598                auto_scroll = true;
 3599            }
 3600            2 => {
 3601                let position = display_map
 3602                    .clip_point(position, Bias::Left)
 3603                    .to_offset(&display_map, Bias::Left);
 3604                let (range, _) = buffer.surrounding_word(position, None);
 3605                start = buffer.anchor_before(range.start);
 3606                end = buffer.anchor_before(range.end);
 3607                mode = SelectMode::Word(start..end);
 3608                auto_scroll = true;
 3609            }
 3610            3 => {
 3611                let position = display_map
 3612                    .clip_point(position, Bias::Left)
 3613                    .to_point(&display_map);
 3614                let line_start = display_map.prev_line_boundary(position).0;
 3615                let next_line_start = buffer.clip_point(
 3616                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3617                    Bias::Left,
 3618                );
 3619                start = buffer.anchor_before(line_start);
 3620                end = buffer.anchor_before(next_line_start);
 3621                mode = SelectMode::Line(start..end);
 3622                auto_scroll = true;
 3623            }
 3624            _ => {
 3625                start = buffer.anchor_before(0);
 3626                end = buffer.anchor_before(buffer.len());
 3627                mode = SelectMode::All;
 3628                auto_scroll = false;
 3629            }
 3630        }
 3631        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3632
 3633        let point_to_delete: Option<usize> = {
 3634            let selected_points: Vec<Selection<Point>> =
 3635                self.selections.disjoint_in_range(start..end, cx);
 3636
 3637            if !add || click_count > 1 {
 3638                None
 3639            } else if !selected_points.is_empty() {
 3640                Some(selected_points[0].id)
 3641            } else {
 3642                let clicked_point_already_selected =
 3643                    self.selections.disjoint_anchors().iter().find(|selection| {
 3644                        selection.start.to_point(buffer) == start.to_point(buffer)
 3645                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3646                    });
 3647
 3648                clicked_point_already_selected.map(|selection| selection.id)
 3649            }
 3650        };
 3651
 3652        let selections_count = self.selections.count();
 3653        let effects = if auto_scroll {
 3654            SelectionEffects::default()
 3655        } else {
 3656            SelectionEffects::no_scroll()
 3657        };
 3658
 3659        self.change_selections(effects, window, cx, |s| {
 3660            if let Some(point_to_delete) = point_to_delete {
 3661                s.delete(point_to_delete);
 3662
 3663                if selections_count == 1 {
 3664                    s.set_pending_anchor_range(start..end, mode);
 3665                }
 3666            } else {
 3667                if !add {
 3668                    s.clear_disjoint();
 3669                }
 3670
 3671                s.set_pending_anchor_range(start..end, mode);
 3672            }
 3673        });
 3674    }
 3675
 3676    fn begin_columnar_selection(
 3677        &mut self,
 3678        position: DisplayPoint,
 3679        goal_column: u32,
 3680        reset: bool,
 3681        mode: ColumnarMode,
 3682        window: &mut Window,
 3683        cx: &mut Context<Self>,
 3684    ) {
 3685        if !self.focus_handle.is_focused(window) {
 3686            self.last_focused_descendant = None;
 3687            window.focus(&self.focus_handle);
 3688        }
 3689
 3690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3691
 3692        if reset {
 3693            let pointer_position = display_map
 3694                .buffer_snapshot()
 3695                .anchor_before(position.to_point(&display_map));
 3696
 3697            self.change_selections(
 3698                SelectionEffects::scroll(Autoscroll::newest()),
 3699                window,
 3700                cx,
 3701                |s| {
 3702                    s.clear_disjoint();
 3703                    s.set_pending_anchor_range(
 3704                        pointer_position..pointer_position,
 3705                        SelectMode::Character,
 3706                    );
 3707                },
 3708            );
 3709        };
 3710
 3711        let tail = self.selections.newest::<Point>(cx).tail();
 3712        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3713        self.columnar_selection_state = match mode {
 3714            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3715                selection_tail: selection_anchor,
 3716                display_point: if reset {
 3717                    if position.column() != goal_column {
 3718                        Some(DisplayPoint::new(position.row(), goal_column))
 3719                    } else {
 3720                        None
 3721                    }
 3722                } else {
 3723                    None
 3724                },
 3725            }),
 3726            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3727                selection_tail: selection_anchor,
 3728            }),
 3729        };
 3730
 3731        if !reset {
 3732            self.select_columns(position, goal_column, &display_map, window, cx);
 3733        }
 3734    }
 3735
 3736    fn update_selection(
 3737        &mut self,
 3738        position: DisplayPoint,
 3739        goal_column: u32,
 3740        scroll_delta: gpui::Point<f32>,
 3741        window: &mut Window,
 3742        cx: &mut Context<Self>,
 3743    ) {
 3744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3745
 3746        if self.columnar_selection_state.is_some() {
 3747            self.select_columns(position, goal_column, &display_map, window, cx);
 3748        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3749            let buffer = display_map.buffer_snapshot();
 3750            let head;
 3751            let tail;
 3752            let mode = self.selections.pending_mode().unwrap();
 3753            match &mode {
 3754                SelectMode::Character => {
 3755                    head = position.to_point(&display_map);
 3756                    tail = pending.tail().to_point(buffer);
 3757                }
 3758                SelectMode::Word(original_range) => {
 3759                    let offset = display_map
 3760                        .clip_point(position, Bias::Left)
 3761                        .to_offset(&display_map, Bias::Left);
 3762                    let original_range = original_range.to_offset(buffer);
 3763
 3764                    let head_offset = if buffer.is_inside_word(offset, None)
 3765                        || original_range.contains(&offset)
 3766                    {
 3767                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3768                        if word_range.start < original_range.start {
 3769                            word_range.start
 3770                        } else {
 3771                            word_range.end
 3772                        }
 3773                    } else {
 3774                        offset
 3775                    };
 3776
 3777                    head = head_offset.to_point(buffer);
 3778                    if head_offset <= original_range.start {
 3779                        tail = original_range.end.to_point(buffer);
 3780                    } else {
 3781                        tail = original_range.start.to_point(buffer);
 3782                    }
 3783                }
 3784                SelectMode::Line(original_range) => {
 3785                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3786
 3787                    let position = display_map
 3788                        .clip_point(position, Bias::Left)
 3789                        .to_point(&display_map);
 3790                    let line_start = display_map.prev_line_boundary(position).0;
 3791                    let next_line_start = buffer.clip_point(
 3792                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3793                        Bias::Left,
 3794                    );
 3795
 3796                    if line_start < original_range.start {
 3797                        head = line_start
 3798                    } else {
 3799                        head = next_line_start
 3800                    }
 3801
 3802                    if head <= original_range.start {
 3803                        tail = original_range.end;
 3804                    } else {
 3805                        tail = original_range.start;
 3806                    }
 3807                }
 3808                SelectMode::All => {
 3809                    return;
 3810                }
 3811            };
 3812
 3813            if head < tail {
 3814                pending.start = buffer.anchor_before(head);
 3815                pending.end = buffer.anchor_before(tail);
 3816                pending.reversed = true;
 3817            } else {
 3818                pending.start = buffer.anchor_before(tail);
 3819                pending.end = buffer.anchor_before(head);
 3820                pending.reversed = false;
 3821            }
 3822
 3823            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3824                s.set_pending(pending.clone(), mode);
 3825            });
 3826        } else {
 3827            log::error!("update_selection dispatched with no pending selection");
 3828            return;
 3829        }
 3830
 3831        self.apply_scroll_delta(scroll_delta, window, cx);
 3832        cx.notify();
 3833    }
 3834
 3835    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3836        self.columnar_selection_state.take();
 3837        if let Some(pending_mode) = self.selections.pending_mode() {
 3838            let selections = self.selections.all::<usize>(cx);
 3839            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3840                s.select(selections);
 3841                s.clear_pending();
 3842                if s.is_extending() {
 3843                    s.set_is_extending(false);
 3844                } else {
 3845                    s.set_select_mode(pending_mode);
 3846                }
 3847            });
 3848        }
 3849    }
 3850
 3851    fn select_columns(
 3852        &mut self,
 3853        head: DisplayPoint,
 3854        goal_column: u32,
 3855        display_map: &DisplaySnapshot,
 3856        window: &mut Window,
 3857        cx: &mut Context<Self>,
 3858    ) {
 3859        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3860            return;
 3861        };
 3862
 3863        let tail = match columnar_state {
 3864            ColumnarSelectionState::FromMouse {
 3865                selection_tail,
 3866                display_point,
 3867            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3868            ColumnarSelectionState::FromSelection { selection_tail } => {
 3869                selection_tail.to_display_point(display_map)
 3870            }
 3871        };
 3872
 3873        let start_row = cmp::min(tail.row(), head.row());
 3874        let end_row = cmp::max(tail.row(), head.row());
 3875        let start_column = cmp::min(tail.column(), goal_column);
 3876        let end_column = cmp::max(tail.column(), goal_column);
 3877        let reversed = start_column < tail.column();
 3878
 3879        let selection_ranges = (start_row.0..=end_row.0)
 3880            .map(DisplayRow)
 3881            .filter_map(|row| {
 3882                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3883                    || start_column <= display_map.line_len(row))
 3884                    && !display_map.is_block_line(row)
 3885                {
 3886                    let start = display_map
 3887                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3888                        .to_point(display_map);
 3889                    let end = display_map
 3890                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3891                        .to_point(display_map);
 3892                    if reversed {
 3893                        Some(end..start)
 3894                    } else {
 3895                        Some(start..end)
 3896                    }
 3897                } else {
 3898                    None
 3899                }
 3900            })
 3901            .collect::<Vec<_>>();
 3902
 3903        let ranges = match columnar_state {
 3904            ColumnarSelectionState::FromMouse { .. } => {
 3905                let mut non_empty_ranges = selection_ranges
 3906                    .iter()
 3907                    .filter(|selection_range| selection_range.start != selection_range.end)
 3908                    .peekable();
 3909                if non_empty_ranges.peek().is_some() {
 3910                    non_empty_ranges.cloned().collect()
 3911                } else {
 3912                    selection_ranges
 3913                }
 3914            }
 3915            _ => selection_ranges,
 3916        };
 3917
 3918        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3919            s.select_ranges(ranges);
 3920        });
 3921        cx.notify();
 3922    }
 3923
 3924    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3925        self.selections
 3926            .all_adjusted(cx)
 3927            .iter()
 3928            .any(|selection| !selection.is_empty())
 3929    }
 3930
 3931    pub fn has_pending_nonempty_selection(&self) -> bool {
 3932        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3933            Some(Selection { start, end, .. }) => start != end,
 3934            None => false,
 3935        };
 3936
 3937        pending_nonempty_selection
 3938            || (self.columnar_selection_state.is_some()
 3939                && self.selections.disjoint_anchors().len() > 1)
 3940    }
 3941
 3942    pub fn has_pending_selection(&self) -> bool {
 3943        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3944    }
 3945
 3946    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3947        self.selection_mark_mode = false;
 3948        self.selection_drag_state = SelectionDragState::None;
 3949
 3950        if self.clear_expanded_diff_hunks(cx) {
 3951            cx.notify();
 3952            return;
 3953        }
 3954        if self.dismiss_menus_and_popups(true, window, cx) {
 3955            return;
 3956        }
 3957
 3958        if self.mode.is_full()
 3959            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3960        {
 3961            return;
 3962        }
 3963
 3964        cx.propagate();
 3965    }
 3966
 3967    pub fn dismiss_menus_and_popups(
 3968        &mut self,
 3969        is_user_requested: bool,
 3970        window: &mut Window,
 3971        cx: &mut Context<Self>,
 3972    ) -> bool {
 3973        if self.take_rename(false, window, cx).is_some() {
 3974            return true;
 3975        }
 3976
 3977        if hide_hover(self, cx) {
 3978            return true;
 3979        }
 3980
 3981        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3982            return true;
 3983        }
 3984
 3985        if self.hide_context_menu(window, cx).is_some() {
 3986            return true;
 3987        }
 3988
 3989        if self.mouse_context_menu.take().is_some() {
 3990            return true;
 3991        }
 3992
 3993        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3994            return true;
 3995        }
 3996
 3997        if self.snippet_stack.pop().is_some() {
 3998            return true;
 3999        }
 4000
 4001        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4002            self.dismiss_diagnostics(cx);
 4003            return true;
 4004        }
 4005
 4006        false
 4007    }
 4008
 4009    fn linked_editing_ranges_for(
 4010        &self,
 4011        selection: Range<text::Anchor>,
 4012        cx: &App,
 4013    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4014        if self.linked_edit_ranges.is_empty() {
 4015            return None;
 4016        }
 4017        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4018            selection.end.buffer_id.and_then(|end_buffer_id| {
 4019                if selection.start.buffer_id != Some(end_buffer_id) {
 4020                    return None;
 4021                }
 4022                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4023                let snapshot = buffer.read(cx).snapshot();
 4024                self.linked_edit_ranges
 4025                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4026                    .map(|ranges| (ranges, snapshot, buffer))
 4027            })?;
 4028        use text::ToOffset as TO;
 4029        // find offset from the start of current range to current cursor position
 4030        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4031
 4032        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4033        let start_difference = start_offset - start_byte_offset;
 4034        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4035        let end_difference = end_offset - start_byte_offset;
 4036        // Current range has associated linked ranges.
 4037        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4038        for range in linked_ranges.iter() {
 4039            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4040            let end_offset = start_offset + end_difference;
 4041            let start_offset = start_offset + start_difference;
 4042            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4043                continue;
 4044            }
 4045            if self.selections.disjoint_anchor_ranges().any(|s| {
 4046                if s.start.buffer_id != selection.start.buffer_id
 4047                    || s.end.buffer_id != selection.end.buffer_id
 4048                {
 4049                    return false;
 4050                }
 4051                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4052                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4053            }) {
 4054                continue;
 4055            }
 4056            let start = buffer_snapshot.anchor_after(start_offset);
 4057            let end = buffer_snapshot.anchor_after(end_offset);
 4058            linked_edits
 4059                .entry(buffer.clone())
 4060                .or_default()
 4061                .push(start..end);
 4062        }
 4063        Some(linked_edits)
 4064    }
 4065
 4066    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4067        let text: Arc<str> = text.into();
 4068
 4069        if self.read_only(cx) {
 4070            return;
 4071        }
 4072
 4073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4074
 4075        let selections = self.selections.all_adjusted(cx);
 4076        let mut bracket_inserted = false;
 4077        let mut edits = Vec::new();
 4078        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4079        let mut new_selections = Vec::with_capacity(selections.len());
 4080        let mut new_autoclose_regions = Vec::new();
 4081        let snapshot = self.buffer.read(cx).read(cx);
 4082        let mut clear_linked_edit_ranges = false;
 4083
 4084        for (selection, autoclose_region) in
 4085            self.selections_with_autoclose_regions(selections, &snapshot)
 4086        {
 4087            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4088                // Determine if the inserted text matches the opening or closing
 4089                // bracket of any of this language's bracket pairs.
 4090                let mut bracket_pair = None;
 4091                let mut is_bracket_pair_start = false;
 4092                let mut is_bracket_pair_end = false;
 4093                if !text.is_empty() {
 4094                    let mut bracket_pair_matching_end = None;
 4095                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4096                    //  and they are removing the character that triggered IME popup.
 4097                    for (pair, enabled) in scope.brackets() {
 4098                        if !pair.close && !pair.surround {
 4099                            continue;
 4100                        }
 4101
 4102                        if enabled && pair.start.ends_with(text.as_ref()) {
 4103                            let prefix_len = pair.start.len() - text.len();
 4104                            let preceding_text_matches_prefix = prefix_len == 0
 4105                                || (selection.start.column >= (prefix_len as u32)
 4106                                    && snapshot.contains_str_at(
 4107                                        Point::new(
 4108                                            selection.start.row,
 4109                                            selection.start.column - (prefix_len as u32),
 4110                                        ),
 4111                                        &pair.start[..prefix_len],
 4112                                    ));
 4113                            if preceding_text_matches_prefix {
 4114                                bracket_pair = Some(pair.clone());
 4115                                is_bracket_pair_start = true;
 4116                                break;
 4117                            }
 4118                        }
 4119                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4120                        {
 4121                            // take first bracket pair matching end, but don't break in case a later bracket
 4122                            // pair matches start
 4123                            bracket_pair_matching_end = Some(pair.clone());
 4124                        }
 4125                    }
 4126                    if let Some(end) = bracket_pair_matching_end
 4127                        && bracket_pair.is_none()
 4128                    {
 4129                        bracket_pair = Some(end);
 4130                        is_bracket_pair_end = true;
 4131                    }
 4132                }
 4133
 4134                if let Some(bracket_pair) = bracket_pair {
 4135                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4136                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4137                    let auto_surround =
 4138                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4139                    if selection.is_empty() {
 4140                        if is_bracket_pair_start {
 4141                            // If the inserted text is a suffix of an opening bracket and the
 4142                            // selection is preceded by the rest of the opening bracket, then
 4143                            // insert the closing bracket.
 4144                            let following_text_allows_autoclose = snapshot
 4145                                .chars_at(selection.start)
 4146                                .next()
 4147                                .is_none_or(|c| scope.should_autoclose_before(c));
 4148
 4149                            let preceding_text_allows_autoclose = selection.start.column == 0
 4150                                || snapshot
 4151                                    .reversed_chars_at(selection.start)
 4152                                    .next()
 4153                                    .is_none_or(|c| {
 4154                                        bracket_pair.start != bracket_pair.end
 4155                                            || !snapshot
 4156                                                .char_classifier_at(selection.start)
 4157                                                .is_word(c)
 4158                                    });
 4159
 4160                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4161                                && bracket_pair.start.len() == 1
 4162                            {
 4163                                let target = bracket_pair.start.chars().next().unwrap();
 4164                                let current_line_count = snapshot
 4165                                    .reversed_chars_at(selection.start)
 4166                                    .take_while(|&c| c != '\n')
 4167                                    .filter(|&c| c == target)
 4168                                    .count();
 4169                                current_line_count % 2 == 1
 4170                            } else {
 4171                                false
 4172                            };
 4173
 4174                            if autoclose
 4175                                && bracket_pair.close
 4176                                && following_text_allows_autoclose
 4177                                && preceding_text_allows_autoclose
 4178                                && !is_closing_quote
 4179                            {
 4180                                let anchor = snapshot.anchor_before(selection.end);
 4181                                new_selections.push((selection.map(|_| anchor), text.len()));
 4182                                new_autoclose_regions.push((
 4183                                    anchor,
 4184                                    text.len(),
 4185                                    selection.id,
 4186                                    bracket_pair.clone(),
 4187                                ));
 4188                                edits.push((
 4189                                    selection.range(),
 4190                                    format!("{}{}", text, bracket_pair.end).into(),
 4191                                ));
 4192                                bracket_inserted = true;
 4193                                continue;
 4194                            }
 4195                        }
 4196
 4197                        if let Some(region) = autoclose_region {
 4198                            // If the selection is followed by an auto-inserted closing bracket,
 4199                            // then don't insert that closing bracket again; just move the selection
 4200                            // past the closing bracket.
 4201                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4202                                && text.as_ref() == region.pair.end.as_str()
 4203                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4204                            if should_skip {
 4205                                let anchor = snapshot.anchor_after(selection.end);
 4206                                new_selections
 4207                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4208                                continue;
 4209                            }
 4210                        }
 4211
 4212                        let always_treat_brackets_as_autoclosed = snapshot
 4213                            .language_settings_at(selection.start, cx)
 4214                            .always_treat_brackets_as_autoclosed;
 4215                        if always_treat_brackets_as_autoclosed
 4216                            && is_bracket_pair_end
 4217                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4218                        {
 4219                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4220                            // and the inserted text is a closing bracket and the selection is followed
 4221                            // by the closing bracket then move the selection past the closing bracket.
 4222                            let anchor = snapshot.anchor_after(selection.end);
 4223                            new_selections.push((selection.map(|_| anchor), text.len()));
 4224                            continue;
 4225                        }
 4226                    }
 4227                    // If an opening bracket is 1 character long and is typed while
 4228                    // text is selected, then surround that text with the bracket pair.
 4229                    else if auto_surround
 4230                        && bracket_pair.surround
 4231                        && is_bracket_pair_start
 4232                        && bracket_pair.start.chars().count() == 1
 4233                    {
 4234                        edits.push((selection.start..selection.start, text.clone()));
 4235                        edits.push((
 4236                            selection.end..selection.end,
 4237                            bracket_pair.end.as_str().into(),
 4238                        ));
 4239                        bracket_inserted = true;
 4240                        new_selections.push((
 4241                            Selection {
 4242                                id: selection.id,
 4243                                start: snapshot.anchor_after(selection.start),
 4244                                end: snapshot.anchor_before(selection.end),
 4245                                reversed: selection.reversed,
 4246                                goal: selection.goal,
 4247                            },
 4248                            0,
 4249                        ));
 4250                        continue;
 4251                    }
 4252                }
 4253            }
 4254
 4255            if self.auto_replace_emoji_shortcode
 4256                && selection.is_empty()
 4257                && text.as_ref().ends_with(':')
 4258                && let Some(possible_emoji_short_code) =
 4259                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4260                && !possible_emoji_short_code.is_empty()
 4261                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4262            {
 4263                let emoji_shortcode_start = Point::new(
 4264                    selection.start.row,
 4265                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4266                );
 4267
 4268                // Remove shortcode from buffer
 4269                edits.push((
 4270                    emoji_shortcode_start..selection.start,
 4271                    "".to_string().into(),
 4272                ));
 4273                new_selections.push((
 4274                    Selection {
 4275                        id: selection.id,
 4276                        start: snapshot.anchor_after(emoji_shortcode_start),
 4277                        end: snapshot.anchor_before(selection.start),
 4278                        reversed: selection.reversed,
 4279                        goal: selection.goal,
 4280                    },
 4281                    0,
 4282                ));
 4283
 4284                // Insert emoji
 4285                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4286                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4287                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4288
 4289                continue;
 4290            }
 4291
 4292            // If not handling any auto-close operation, then just replace the selected
 4293            // text with the given input and move the selection to the end of the
 4294            // newly inserted text.
 4295            let anchor = snapshot.anchor_after(selection.end);
 4296            if !self.linked_edit_ranges.is_empty() {
 4297                let start_anchor = snapshot.anchor_before(selection.start);
 4298
 4299                let is_word_char = text.chars().next().is_none_or(|char| {
 4300                    let classifier = snapshot
 4301                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4302                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4303                    classifier.is_word(char)
 4304                });
 4305
 4306                if is_word_char {
 4307                    if let Some(ranges) = self
 4308                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4309                    {
 4310                        for (buffer, edits) in ranges {
 4311                            linked_edits
 4312                                .entry(buffer.clone())
 4313                                .or_default()
 4314                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4315                        }
 4316                    }
 4317                } else {
 4318                    clear_linked_edit_ranges = true;
 4319                }
 4320            }
 4321
 4322            new_selections.push((selection.map(|_| anchor), 0));
 4323            edits.push((selection.start..selection.end, text.clone()));
 4324        }
 4325
 4326        drop(snapshot);
 4327
 4328        self.transact(window, cx, |this, window, cx| {
 4329            if clear_linked_edit_ranges {
 4330                this.linked_edit_ranges.clear();
 4331            }
 4332            let initial_buffer_versions =
 4333                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4334
 4335            this.buffer.update(cx, |buffer, cx| {
 4336                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4337            });
 4338            for (buffer, edits) in linked_edits {
 4339                buffer.update(cx, |buffer, cx| {
 4340                    let snapshot = buffer.snapshot();
 4341                    let edits = edits
 4342                        .into_iter()
 4343                        .map(|(range, text)| {
 4344                            use text::ToPoint as TP;
 4345                            let end_point = TP::to_point(&range.end, &snapshot);
 4346                            let start_point = TP::to_point(&range.start, &snapshot);
 4347                            (start_point..end_point, text)
 4348                        })
 4349                        .sorted_by_key(|(range, _)| range.start);
 4350                    buffer.edit(edits, None, cx);
 4351                })
 4352            }
 4353            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4354            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4355            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4356            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4357                .zip(new_selection_deltas)
 4358                .map(|(selection, delta)| Selection {
 4359                    id: selection.id,
 4360                    start: selection.start + delta,
 4361                    end: selection.end + delta,
 4362                    reversed: selection.reversed,
 4363                    goal: SelectionGoal::None,
 4364                })
 4365                .collect::<Vec<_>>();
 4366
 4367            let mut i = 0;
 4368            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4369                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4370                let start = map.buffer_snapshot().anchor_before(position);
 4371                let end = map.buffer_snapshot().anchor_after(position);
 4372                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4373                    match existing_state
 4374                        .range
 4375                        .start
 4376                        .cmp(&start, map.buffer_snapshot())
 4377                    {
 4378                        Ordering::Less => i += 1,
 4379                        Ordering::Greater => break,
 4380                        Ordering::Equal => {
 4381                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4382                                Ordering::Less => i += 1,
 4383                                Ordering::Equal => break,
 4384                                Ordering::Greater => break,
 4385                            }
 4386                        }
 4387                    }
 4388                }
 4389                this.autoclose_regions.insert(
 4390                    i,
 4391                    AutocloseRegion {
 4392                        selection_id,
 4393                        range: start..end,
 4394                        pair,
 4395                    },
 4396                );
 4397            }
 4398
 4399            let had_active_edit_prediction = this.has_active_edit_prediction();
 4400            this.change_selections(
 4401                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4402                window,
 4403                cx,
 4404                |s| s.select(new_selections),
 4405            );
 4406
 4407            if !bracket_inserted
 4408                && let Some(on_type_format_task) =
 4409                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4410            {
 4411                on_type_format_task.detach_and_log_err(cx);
 4412            }
 4413
 4414            let editor_settings = EditorSettings::get_global(cx);
 4415            if bracket_inserted
 4416                && (editor_settings.auto_signature_help
 4417                    || editor_settings.show_signature_help_after_edits)
 4418            {
 4419                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4420            }
 4421
 4422            let trigger_in_words =
 4423                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4424            if this.hard_wrap.is_some() {
 4425                let latest: Range<Point> = this.selections.newest(cx).range();
 4426                if latest.is_empty()
 4427                    && this
 4428                        .buffer()
 4429                        .read(cx)
 4430                        .snapshot(cx)
 4431                        .line_len(MultiBufferRow(latest.start.row))
 4432                        == latest.start.column
 4433                {
 4434                    this.rewrap_impl(
 4435                        RewrapOptions {
 4436                            override_language_settings: true,
 4437                            preserve_existing_whitespace: true,
 4438                        },
 4439                        cx,
 4440                    )
 4441                }
 4442            }
 4443            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4444            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4445            this.refresh_edit_prediction(true, false, window, cx);
 4446            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4447        });
 4448    }
 4449
 4450    fn find_possible_emoji_shortcode_at_position(
 4451        snapshot: &MultiBufferSnapshot,
 4452        position: Point,
 4453    ) -> Option<String> {
 4454        let mut chars = Vec::new();
 4455        let mut found_colon = false;
 4456        for char in snapshot.reversed_chars_at(position).take(100) {
 4457            // Found a possible emoji shortcode in the middle of the buffer
 4458            if found_colon {
 4459                if char.is_whitespace() {
 4460                    chars.reverse();
 4461                    return Some(chars.iter().collect());
 4462                }
 4463                // If the previous character is not a whitespace, we are in the middle of a word
 4464                // and we only want to complete the shortcode if the word is made up of other emojis
 4465                let mut containing_word = String::new();
 4466                for ch in snapshot
 4467                    .reversed_chars_at(position)
 4468                    .skip(chars.len() + 1)
 4469                    .take(100)
 4470                {
 4471                    if ch.is_whitespace() {
 4472                        break;
 4473                    }
 4474                    containing_word.push(ch);
 4475                }
 4476                let containing_word = containing_word.chars().rev().collect::<String>();
 4477                if util::word_consists_of_emojis(containing_word.as_str()) {
 4478                    chars.reverse();
 4479                    return Some(chars.iter().collect());
 4480                }
 4481            }
 4482
 4483            if char.is_whitespace() || !char.is_ascii() {
 4484                return None;
 4485            }
 4486            if char == ':' {
 4487                found_colon = true;
 4488            } else {
 4489                chars.push(char);
 4490            }
 4491        }
 4492        // Found a possible emoji shortcode at the beginning of the buffer
 4493        chars.reverse();
 4494        Some(chars.iter().collect())
 4495    }
 4496
 4497    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4498        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4499        self.transact(window, cx, |this, window, cx| {
 4500            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4501                let selections = this.selections.all::<usize>(cx);
 4502                let multi_buffer = this.buffer.read(cx);
 4503                let buffer = multi_buffer.snapshot(cx);
 4504                selections
 4505                    .iter()
 4506                    .map(|selection| {
 4507                        let start_point = selection.start.to_point(&buffer);
 4508                        let mut existing_indent =
 4509                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4510                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4511                        let start = selection.start;
 4512                        let end = selection.end;
 4513                        let selection_is_empty = start == end;
 4514                        let language_scope = buffer.language_scope_at(start);
 4515                        let (
 4516                            comment_delimiter,
 4517                            doc_delimiter,
 4518                            insert_extra_newline,
 4519                            indent_on_newline,
 4520                            indent_on_extra_newline,
 4521                        ) = if let Some(language) = &language_scope {
 4522                            let mut insert_extra_newline =
 4523                                insert_extra_newline_brackets(&buffer, start..end, language)
 4524                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4525
 4526                            // Comment extension on newline is allowed only for cursor selections
 4527                            let comment_delimiter = maybe!({
 4528                                if !selection_is_empty {
 4529                                    return None;
 4530                                }
 4531
 4532                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4533                                    return None;
 4534                                }
 4535
 4536                                let delimiters = language.line_comment_prefixes();
 4537                                let max_len_of_delimiter =
 4538                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4539                                let (snapshot, range) =
 4540                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4541
 4542                                let num_of_whitespaces = snapshot
 4543                                    .chars_for_range(range.clone())
 4544                                    .take_while(|c| c.is_whitespace())
 4545                                    .count();
 4546                                let comment_candidate = snapshot
 4547                                    .chars_for_range(range.clone())
 4548                                    .skip(num_of_whitespaces)
 4549                                    .take(max_len_of_delimiter)
 4550                                    .collect::<String>();
 4551                                let (delimiter, trimmed_len) = delimiters
 4552                                    .iter()
 4553                                    .filter_map(|delimiter| {
 4554                                        let prefix = delimiter.trim_end();
 4555                                        if comment_candidate.starts_with(prefix) {
 4556                                            Some((delimiter, prefix.len()))
 4557                                        } else {
 4558                                            None
 4559                                        }
 4560                                    })
 4561                                    .max_by_key(|(_, len)| *len)?;
 4562
 4563                                if let Some(BlockCommentConfig {
 4564                                    start: block_start, ..
 4565                                }) = language.block_comment()
 4566                                {
 4567                                    let block_start_trimmed = block_start.trim_end();
 4568                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4569                                        let line_content = snapshot
 4570                                            .chars_for_range(range)
 4571                                            .skip(num_of_whitespaces)
 4572                                            .take(block_start_trimmed.len())
 4573                                            .collect::<String>();
 4574
 4575                                        if line_content.starts_with(block_start_trimmed) {
 4576                                            return None;
 4577                                        }
 4578                                    }
 4579                                }
 4580
 4581                                let cursor_is_placed_after_comment_marker =
 4582                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4583                                if cursor_is_placed_after_comment_marker {
 4584                                    Some(delimiter.clone())
 4585                                } else {
 4586                                    None
 4587                                }
 4588                            });
 4589
 4590                            let mut indent_on_newline = IndentSize::spaces(0);
 4591                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4592
 4593                            let doc_delimiter = maybe!({
 4594                                if !selection_is_empty {
 4595                                    return None;
 4596                                }
 4597
 4598                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4599                                    return None;
 4600                                }
 4601
 4602                                let BlockCommentConfig {
 4603                                    start: start_tag,
 4604                                    end: end_tag,
 4605                                    prefix: delimiter,
 4606                                    tab_size: len,
 4607                                } = language.documentation_comment()?;
 4608                                let is_within_block_comment = buffer
 4609                                    .language_scope_at(start_point)
 4610                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4611                                if !is_within_block_comment {
 4612                                    return None;
 4613                                }
 4614
 4615                                let (snapshot, range) =
 4616                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4617
 4618                                let num_of_whitespaces = snapshot
 4619                                    .chars_for_range(range.clone())
 4620                                    .take_while(|c| c.is_whitespace())
 4621                                    .count();
 4622
 4623                                // 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.
 4624                                let column = start_point.column;
 4625                                let cursor_is_after_start_tag = {
 4626                                    let start_tag_len = start_tag.len();
 4627                                    let start_tag_line = snapshot
 4628                                        .chars_for_range(range.clone())
 4629                                        .skip(num_of_whitespaces)
 4630                                        .take(start_tag_len)
 4631                                        .collect::<String>();
 4632                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4633                                        num_of_whitespaces + start_tag_len <= column as usize
 4634                                    } else {
 4635                                        false
 4636                                    }
 4637                                };
 4638
 4639                                let cursor_is_after_delimiter = {
 4640                                    let delimiter_trim = delimiter.trim_end();
 4641                                    let delimiter_line = snapshot
 4642                                        .chars_for_range(range.clone())
 4643                                        .skip(num_of_whitespaces)
 4644                                        .take(delimiter_trim.len())
 4645                                        .collect::<String>();
 4646                                    if delimiter_line.starts_with(delimiter_trim) {
 4647                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4648                                    } else {
 4649                                        false
 4650                                    }
 4651                                };
 4652
 4653                                let cursor_is_before_end_tag_if_exists = {
 4654                                    let mut char_position = 0u32;
 4655                                    let mut end_tag_offset = None;
 4656
 4657                                    'outer: for chunk in snapshot.text_for_range(range) {
 4658                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4659                                            let chars_before_match =
 4660                                                chunk[..byte_pos].chars().count() as u32;
 4661                                            end_tag_offset =
 4662                                                Some(char_position + chars_before_match);
 4663                                            break 'outer;
 4664                                        }
 4665                                        char_position += chunk.chars().count() as u32;
 4666                                    }
 4667
 4668                                    if let Some(end_tag_offset) = end_tag_offset {
 4669                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4670                                        if cursor_is_after_start_tag {
 4671                                            if cursor_is_before_end_tag {
 4672                                                insert_extra_newline = true;
 4673                                            }
 4674                                            let cursor_is_at_start_of_end_tag =
 4675                                                column == end_tag_offset;
 4676                                            if cursor_is_at_start_of_end_tag {
 4677                                                indent_on_extra_newline.len = *len;
 4678                                            }
 4679                                        }
 4680                                        cursor_is_before_end_tag
 4681                                    } else {
 4682                                        true
 4683                                    }
 4684                                };
 4685
 4686                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4687                                    && cursor_is_before_end_tag_if_exists
 4688                                {
 4689                                    if cursor_is_after_start_tag {
 4690                                        indent_on_newline.len = *len;
 4691                                    }
 4692                                    Some(delimiter.clone())
 4693                                } else {
 4694                                    None
 4695                                }
 4696                            });
 4697
 4698                            (
 4699                                comment_delimiter,
 4700                                doc_delimiter,
 4701                                insert_extra_newline,
 4702                                indent_on_newline,
 4703                                indent_on_extra_newline,
 4704                            )
 4705                        } else {
 4706                            (
 4707                                None,
 4708                                None,
 4709                                false,
 4710                                IndentSize::default(),
 4711                                IndentSize::default(),
 4712                            )
 4713                        };
 4714
 4715                        let prevent_auto_indent = doc_delimiter.is_some();
 4716                        let delimiter = comment_delimiter.or(doc_delimiter);
 4717
 4718                        let capacity_for_delimiter =
 4719                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4720                        let mut new_text = String::with_capacity(
 4721                            1 + capacity_for_delimiter
 4722                                + existing_indent.len as usize
 4723                                + indent_on_newline.len as usize
 4724                                + indent_on_extra_newline.len as usize,
 4725                        );
 4726                        new_text.push('\n');
 4727                        new_text.extend(existing_indent.chars());
 4728                        new_text.extend(indent_on_newline.chars());
 4729
 4730                        if let Some(delimiter) = &delimiter {
 4731                            new_text.push_str(delimiter);
 4732                        }
 4733
 4734                        if insert_extra_newline {
 4735                            new_text.push('\n');
 4736                            new_text.extend(existing_indent.chars());
 4737                            new_text.extend(indent_on_extra_newline.chars());
 4738                        }
 4739
 4740                        let anchor = buffer.anchor_after(end);
 4741                        let new_selection = selection.map(|_| anchor);
 4742                        (
 4743                            ((start..end, new_text), prevent_auto_indent),
 4744                            (insert_extra_newline, new_selection),
 4745                        )
 4746                    })
 4747                    .unzip()
 4748            };
 4749
 4750            let mut auto_indent_edits = Vec::new();
 4751            let mut edits = Vec::new();
 4752            for (edit, prevent_auto_indent) in edits_with_flags {
 4753                if prevent_auto_indent {
 4754                    edits.push(edit);
 4755                } else {
 4756                    auto_indent_edits.push(edit);
 4757                }
 4758            }
 4759            if !edits.is_empty() {
 4760                this.edit(edits, cx);
 4761            }
 4762            if !auto_indent_edits.is_empty() {
 4763                this.edit_with_autoindent(auto_indent_edits, cx);
 4764            }
 4765
 4766            let buffer = this.buffer.read(cx).snapshot(cx);
 4767            let new_selections = selection_info
 4768                .into_iter()
 4769                .map(|(extra_newline_inserted, new_selection)| {
 4770                    let mut cursor = new_selection.end.to_point(&buffer);
 4771                    if extra_newline_inserted {
 4772                        cursor.row -= 1;
 4773                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4774                    }
 4775                    new_selection.map(|_| cursor)
 4776                })
 4777                .collect();
 4778
 4779            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4780            this.refresh_edit_prediction(true, false, window, cx);
 4781        });
 4782    }
 4783
 4784    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4786
 4787        let buffer = self.buffer.read(cx);
 4788        let snapshot = buffer.snapshot(cx);
 4789
 4790        let mut edits = Vec::new();
 4791        let mut rows = Vec::new();
 4792
 4793        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4794            let cursor = selection.head();
 4795            let row = cursor.row;
 4796
 4797            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4798
 4799            let newline = "\n".to_string();
 4800            edits.push((start_of_line..start_of_line, newline));
 4801
 4802            rows.push(row + rows_inserted as u32);
 4803        }
 4804
 4805        self.transact(window, cx, |editor, window, cx| {
 4806            editor.edit(edits, cx);
 4807
 4808            editor.change_selections(Default::default(), window, cx, |s| {
 4809                let mut index = 0;
 4810                s.move_cursors_with(|map, _, _| {
 4811                    let row = rows[index];
 4812                    index += 1;
 4813
 4814                    let point = Point::new(row, 0);
 4815                    let boundary = map.next_line_boundary(point).1;
 4816                    let clipped = map.clip_point(boundary, Bias::Left);
 4817
 4818                    (clipped, SelectionGoal::None)
 4819                });
 4820            });
 4821
 4822            let mut indent_edits = Vec::new();
 4823            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4824            for row in rows {
 4825                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4826                for (row, indent) in indents {
 4827                    if indent.len == 0 {
 4828                        continue;
 4829                    }
 4830
 4831                    let text = match indent.kind {
 4832                        IndentKind::Space => " ".repeat(indent.len as usize),
 4833                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4834                    };
 4835                    let point = Point::new(row.0, 0);
 4836                    indent_edits.push((point..point, text));
 4837                }
 4838            }
 4839            editor.edit(indent_edits, cx);
 4840        });
 4841    }
 4842
 4843    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4845
 4846        let buffer = self.buffer.read(cx);
 4847        let snapshot = buffer.snapshot(cx);
 4848
 4849        let mut edits = Vec::new();
 4850        let mut rows = Vec::new();
 4851        let mut rows_inserted = 0;
 4852
 4853        for selection in self.selections.all_adjusted(cx) {
 4854            let cursor = selection.head();
 4855            let row = cursor.row;
 4856
 4857            let point = Point::new(row + 1, 0);
 4858            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4859
 4860            let newline = "\n".to_string();
 4861            edits.push((start_of_line..start_of_line, newline));
 4862
 4863            rows_inserted += 1;
 4864            rows.push(row + rows_inserted);
 4865        }
 4866
 4867        self.transact(window, cx, |editor, window, cx| {
 4868            editor.edit(edits, cx);
 4869
 4870            editor.change_selections(Default::default(), window, cx, |s| {
 4871                let mut index = 0;
 4872                s.move_cursors_with(|map, _, _| {
 4873                    let row = rows[index];
 4874                    index += 1;
 4875
 4876                    let point = Point::new(row, 0);
 4877                    let boundary = map.next_line_boundary(point).1;
 4878                    let clipped = map.clip_point(boundary, Bias::Left);
 4879
 4880                    (clipped, SelectionGoal::None)
 4881                });
 4882            });
 4883
 4884            let mut indent_edits = Vec::new();
 4885            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4886            for row in rows {
 4887                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4888                for (row, indent) in indents {
 4889                    if indent.len == 0 {
 4890                        continue;
 4891                    }
 4892
 4893                    let text = match indent.kind {
 4894                        IndentKind::Space => " ".repeat(indent.len as usize),
 4895                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4896                    };
 4897                    let point = Point::new(row.0, 0);
 4898                    indent_edits.push((point..point, text));
 4899                }
 4900            }
 4901            editor.edit(indent_edits, cx);
 4902        });
 4903    }
 4904
 4905    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4906        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4907            original_indent_columns: Vec::new(),
 4908        });
 4909        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4910    }
 4911
 4912    fn insert_with_autoindent_mode(
 4913        &mut self,
 4914        text: &str,
 4915        autoindent_mode: Option<AutoindentMode>,
 4916        window: &mut Window,
 4917        cx: &mut Context<Self>,
 4918    ) {
 4919        if self.read_only(cx) {
 4920            return;
 4921        }
 4922
 4923        let text: Arc<str> = text.into();
 4924        self.transact(window, cx, |this, window, cx| {
 4925            let old_selections = this.selections.all_adjusted(cx);
 4926            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4927                let anchors = {
 4928                    let snapshot = buffer.read(cx);
 4929                    old_selections
 4930                        .iter()
 4931                        .map(|s| {
 4932                            let anchor = snapshot.anchor_after(s.head());
 4933                            s.map(|_| anchor)
 4934                        })
 4935                        .collect::<Vec<_>>()
 4936                };
 4937                buffer.edit(
 4938                    old_selections
 4939                        .iter()
 4940                        .map(|s| (s.start..s.end, text.clone())),
 4941                    autoindent_mode,
 4942                    cx,
 4943                );
 4944                anchors
 4945            });
 4946
 4947            this.change_selections(Default::default(), window, cx, |s| {
 4948                s.select_anchors(selection_anchors);
 4949            });
 4950
 4951            cx.notify();
 4952        });
 4953    }
 4954
 4955    fn trigger_completion_on_input(
 4956        &mut self,
 4957        text: &str,
 4958        trigger_in_words: bool,
 4959        window: &mut Window,
 4960        cx: &mut Context<Self>,
 4961    ) {
 4962        let completions_source = self
 4963            .context_menu
 4964            .borrow()
 4965            .as_ref()
 4966            .and_then(|menu| match menu {
 4967                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4968                CodeContextMenu::CodeActions(_) => None,
 4969            });
 4970
 4971        match completions_source {
 4972            Some(CompletionsMenuSource::Words { .. }) => {
 4973                self.open_or_update_completions_menu(
 4974                    Some(CompletionsMenuSource::Words {
 4975                        ignore_threshold: false,
 4976                    }),
 4977                    None,
 4978                    window,
 4979                    cx,
 4980                );
 4981            }
 4982            Some(CompletionsMenuSource::Normal)
 4983            | Some(CompletionsMenuSource::SnippetChoices)
 4984            | None
 4985                if self.is_completion_trigger(
 4986                    text,
 4987                    trigger_in_words,
 4988                    completions_source.is_some(),
 4989                    cx,
 4990                ) =>
 4991            {
 4992                self.show_completions(
 4993                    &ShowCompletions {
 4994                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4995                    },
 4996                    window,
 4997                    cx,
 4998                )
 4999            }
 5000            _ => {
 5001                self.hide_context_menu(window, cx);
 5002            }
 5003        }
 5004    }
 5005
 5006    fn is_completion_trigger(
 5007        &self,
 5008        text: &str,
 5009        trigger_in_words: bool,
 5010        menu_is_open: bool,
 5011        cx: &mut Context<Self>,
 5012    ) -> bool {
 5013        let position = self.selections.newest_anchor().head();
 5014        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5015            return false;
 5016        };
 5017
 5018        if let Some(completion_provider) = &self.completion_provider {
 5019            completion_provider.is_completion_trigger(
 5020                &buffer,
 5021                position.text_anchor,
 5022                text,
 5023                trigger_in_words,
 5024                menu_is_open,
 5025                cx,
 5026            )
 5027        } else {
 5028            false
 5029        }
 5030    }
 5031
 5032    /// If any empty selections is touching the start of its innermost containing autoclose
 5033    /// region, expand it to select the brackets.
 5034    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5035        let selections = self.selections.all::<usize>(cx);
 5036        let buffer = self.buffer.read(cx).read(cx);
 5037        let new_selections = self
 5038            .selections_with_autoclose_regions(selections, &buffer)
 5039            .map(|(mut selection, region)| {
 5040                if !selection.is_empty() {
 5041                    return selection;
 5042                }
 5043
 5044                if let Some(region) = region {
 5045                    let mut range = region.range.to_offset(&buffer);
 5046                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5047                        range.start -= region.pair.start.len();
 5048                        if buffer.contains_str_at(range.start, &region.pair.start)
 5049                            && buffer.contains_str_at(range.end, &region.pair.end)
 5050                        {
 5051                            range.end += region.pair.end.len();
 5052                            selection.start = range.start;
 5053                            selection.end = range.end;
 5054
 5055                            return selection;
 5056                        }
 5057                    }
 5058                }
 5059
 5060                let always_treat_brackets_as_autoclosed = buffer
 5061                    .language_settings_at(selection.start, cx)
 5062                    .always_treat_brackets_as_autoclosed;
 5063
 5064                if !always_treat_brackets_as_autoclosed {
 5065                    return selection;
 5066                }
 5067
 5068                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5069                    for (pair, enabled) in scope.brackets() {
 5070                        if !enabled || !pair.close {
 5071                            continue;
 5072                        }
 5073
 5074                        if buffer.contains_str_at(selection.start, &pair.end) {
 5075                            let pair_start_len = pair.start.len();
 5076                            if buffer.contains_str_at(
 5077                                selection.start.saturating_sub(pair_start_len),
 5078                                &pair.start,
 5079                            ) {
 5080                                selection.start -= pair_start_len;
 5081                                selection.end += pair.end.len();
 5082
 5083                                return selection;
 5084                            }
 5085                        }
 5086                    }
 5087                }
 5088
 5089                selection
 5090            })
 5091            .collect();
 5092
 5093        drop(buffer);
 5094        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5095            selections.select(new_selections)
 5096        });
 5097    }
 5098
 5099    /// Iterate the given selections, and for each one, find the smallest surrounding
 5100    /// autoclose region. This uses the ordering of the selections and the autoclose
 5101    /// regions to avoid repeated comparisons.
 5102    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5103        &'a self,
 5104        selections: impl IntoIterator<Item = Selection<D>>,
 5105        buffer: &'a MultiBufferSnapshot,
 5106    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5107        let mut i = 0;
 5108        let mut regions = self.autoclose_regions.as_slice();
 5109        selections.into_iter().map(move |selection| {
 5110            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5111
 5112            let mut enclosing = None;
 5113            while let Some(pair_state) = regions.get(i) {
 5114                if pair_state.range.end.to_offset(buffer) < range.start {
 5115                    regions = &regions[i + 1..];
 5116                    i = 0;
 5117                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5118                    break;
 5119                } else {
 5120                    if pair_state.selection_id == selection.id {
 5121                        enclosing = Some(pair_state);
 5122                    }
 5123                    i += 1;
 5124                }
 5125            }
 5126
 5127            (selection, enclosing)
 5128        })
 5129    }
 5130
 5131    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5132    fn invalidate_autoclose_regions(
 5133        &mut self,
 5134        mut selections: &[Selection<Anchor>],
 5135        buffer: &MultiBufferSnapshot,
 5136    ) {
 5137        self.autoclose_regions.retain(|state| {
 5138            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5139                return false;
 5140            }
 5141
 5142            let mut i = 0;
 5143            while let Some(selection) = selections.get(i) {
 5144                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5145                    selections = &selections[1..];
 5146                    continue;
 5147                }
 5148                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5149                    break;
 5150                }
 5151                if selection.id == state.selection_id {
 5152                    return true;
 5153                } else {
 5154                    i += 1;
 5155                }
 5156            }
 5157            false
 5158        });
 5159    }
 5160
 5161    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5162        let offset = position.to_offset(buffer);
 5163        let (word_range, kind) =
 5164            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5165        if offset > word_range.start && kind == Some(CharKind::Word) {
 5166            Some(
 5167                buffer
 5168                    .text_for_range(word_range.start..offset)
 5169                    .collect::<String>(),
 5170            )
 5171        } else {
 5172            None
 5173        }
 5174    }
 5175
 5176    pub fn toggle_inline_values(
 5177        &mut self,
 5178        _: &ToggleInlineValues,
 5179        _: &mut Window,
 5180        cx: &mut Context<Self>,
 5181    ) {
 5182        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5183
 5184        self.refresh_inline_values(cx);
 5185    }
 5186
 5187    pub fn toggle_inlay_hints(
 5188        &mut self,
 5189        _: &ToggleInlayHints,
 5190        _: &mut Window,
 5191        cx: &mut Context<Self>,
 5192    ) {
 5193        self.refresh_inlay_hints(
 5194            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5195            cx,
 5196        );
 5197    }
 5198
 5199    pub fn inlay_hints_enabled(&self) -> bool {
 5200        self.inlay_hint_cache.enabled
 5201    }
 5202
 5203    pub fn inline_values_enabled(&self) -> bool {
 5204        self.inline_value_cache.enabled
 5205    }
 5206
 5207    #[cfg(any(test, feature = "test-support"))]
 5208    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5209        self.display_map
 5210            .read(cx)
 5211            .current_inlays()
 5212            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5213            .cloned()
 5214            .collect()
 5215    }
 5216
 5217    #[cfg(any(test, feature = "test-support"))]
 5218    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5219        self.display_map
 5220            .read(cx)
 5221            .current_inlays()
 5222            .cloned()
 5223            .collect()
 5224    }
 5225
 5226    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5227        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5228            return;
 5229        }
 5230
 5231        let reason_description = reason.description();
 5232        let ignore_debounce = matches!(
 5233            reason,
 5234            InlayHintRefreshReason::SettingsChange(_)
 5235                | InlayHintRefreshReason::Toggle(_)
 5236                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5237                | InlayHintRefreshReason::ModifiersChanged(_)
 5238        );
 5239        let (invalidate_cache, required_languages) = match reason {
 5240            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5241                match self.inlay_hint_cache.modifiers_override(enabled) {
 5242                    Some(enabled) => {
 5243                        if enabled {
 5244                            (InvalidationStrategy::RefreshRequested, None)
 5245                        } else {
 5246                            self.clear_inlay_hints(cx);
 5247                            return;
 5248                        }
 5249                    }
 5250                    None => return,
 5251                }
 5252            }
 5253            InlayHintRefreshReason::Toggle(enabled) => {
 5254                if self.inlay_hint_cache.toggle(enabled) {
 5255                    if enabled {
 5256                        (InvalidationStrategy::RefreshRequested, None)
 5257                    } else {
 5258                        self.clear_inlay_hints(cx);
 5259                        return;
 5260                    }
 5261                } else {
 5262                    return;
 5263                }
 5264            }
 5265            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5266                match self.inlay_hint_cache.update_settings(
 5267                    &self.buffer,
 5268                    new_settings,
 5269                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5270                    cx,
 5271                ) {
 5272                    ControlFlow::Break(Some(InlaySplice {
 5273                        to_remove,
 5274                        to_insert,
 5275                    })) => {
 5276                        self.splice_inlays(&to_remove, to_insert, cx);
 5277                        return;
 5278                    }
 5279                    ControlFlow::Break(None) => return,
 5280                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5281                }
 5282            }
 5283            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5284                if let Some(InlaySplice {
 5285                    to_remove,
 5286                    to_insert,
 5287                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5288                {
 5289                    self.splice_inlays(&to_remove, to_insert, cx);
 5290                }
 5291                self.display_map.update(cx, |display_map, _| {
 5292                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5293                });
 5294                return;
 5295            }
 5296            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5297            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5298                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5299            }
 5300            InlayHintRefreshReason::RefreshRequested => {
 5301                (InvalidationStrategy::RefreshRequested, None)
 5302            }
 5303        };
 5304
 5305        if let Some(InlaySplice {
 5306            to_remove,
 5307            to_insert,
 5308        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5309            reason_description,
 5310            self.visible_excerpts(required_languages.as_ref(), cx),
 5311            invalidate_cache,
 5312            ignore_debounce,
 5313            cx,
 5314        ) {
 5315            self.splice_inlays(&to_remove, to_insert, cx);
 5316        }
 5317    }
 5318
 5319    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5320        self.splice_inlays(
 5321            &self
 5322                .visible_inlay_hints(cx)
 5323                .map(|inlay| inlay.id)
 5324                .collect::<Vec<_>>(),
 5325            Vec::new(),
 5326            cx,
 5327        );
 5328    }
 5329
 5330    fn visible_inlay_hints<'a>(
 5331        &'a self,
 5332        cx: &'a Context<Editor>,
 5333    ) -> impl Iterator<Item = &'a Inlay> {
 5334        self.display_map
 5335            .read(cx)
 5336            .current_inlays()
 5337            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5338    }
 5339
 5340    pub fn visible_excerpts(
 5341        &self,
 5342        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5343        cx: &mut Context<Editor>,
 5344    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5345        let Some(project) = self.project() else {
 5346            return HashMap::default();
 5347        };
 5348        let project = project.read(cx);
 5349        let multi_buffer = self.buffer().read(cx);
 5350        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5351        let multi_buffer_visible_start = self
 5352            .scroll_manager
 5353            .anchor()
 5354            .anchor
 5355            .to_point(&multi_buffer_snapshot);
 5356        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5357            multi_buffer_visible_start
 5358                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5359            Bias::Left,
 5360        );
 5361        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5362        multi_buffer_snapshot
 5363            .range_to_buffer_ranges(multi_buffer_visible_range)
 5364            .into_iter()
 5365            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5366            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5367                let buffer_file = project::File::from_dyn(buffer.file())?;
 5368                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5369                let worktree_entry = buffer_worktree
 5370                    .read(cx)
 5371                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5372                if worktree_entry.is_ignored {
 5373                    return None;
 5374                }
 5375
 5376                let language = buffer.language()?;
 5377                if let Some(restrict_to_languages) = restrict_to_languages
 5378                    && !restrict_to_languages.contains(language)
 5379                {
 5380                    return None;
 5381                }
 5382                Some((
 5383                    excerpt_id,
 5384                    (
 5385                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5386                        buffer.version().clone(),
 5387                        excerpt_visible_range,
 5388                    ),
 5389                ))
 5390            })
 5391            .collect()
 5392    }
 5393
 5394    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5395        TextLayoutDetails {
 5396            text_system: window.text_system().clone(),
 5397            editor_style: self.style.clone().unwrap(),
 5398            rem_size: window.rem_size(),
 5399            scroll_anchor: self.scroll_manager.anchor(),
 5400            visible_rows: self.visible_line_count(),
 5401            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5402        }
 5403    }
 5404
 5405    pub fn splice_inlays(
 5406        &self,
 5407        to_remove: &[InlayId],
 5408        to_insert: Vec<Inlay>,
 5409        cx: &mut Context<Self>,
 5410    ) {
 5411        self.display_map.update(cx, |display_map, cx| {
 5412            display_map.splice_inlays(to_remove, to_insert, cx)
 5413        });
 5414        cx.notify();
 5415    }
 5416
 5417    fn trigger_on_type_formatting(
 5418        &self,
 5419        input: String,
 5420        window: &mut Window,
 5421        cx: &mut Context<Self>,
 5422    ) -> Option<Task<Result<()>>> {
 5423        if input.len() != 1 {
 5424            return None;
 5425        }
 5426
 5427        let project = self.project()?;
 5428        let position = self.selections.newest_anchor().head();
 5429        let (buffer, buffer_position) = self
 5430            .buffer
 5431            .read(cx)
 5432            .text_anchor_for_position(position, cx)?;
 5433
 5434        let settings = language_settings::language_settings(
 5435            buffer
 5436                .read(cx)
 5437                .language_at(buffer_position)
 5438                .map(|l| l.name()),
 5439            buffer.read(cx).file(),
 5440            cx,
 5441        );
 5442        if !settings.use_on_type_format {
 5443            return None;
 5444        }
 5445
 5446        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5447        // hence we do LSP request & edit on host side only — add formats to host's history.
 5448        let push_to_lsp_host_history = true;
 5449        // If this is not the host, append its history with new edits.
 5450        let push_to_client_history = project.read(cx).is_via_collab();
 5451
 5452        let on_type_formatting = project.update(cx, |project, cx| {
 5453            project.on_type_format(
 5454                buffer.clone(),
 5455                buffer_position,
 5456                input,
 5457                push_to_lsp_host_history,
 5458                cx,
 5459            )
 5460        });
 5461        Some(cx.spawn_in(window, async move |editor, cx| {
 5462            if let Some(transaction) = on_type_formatting.await? {
 5463                if push_to_client_history {
 5464                    buffer
 5465                        .update(cx, |buffer, _| {
 5466                            buffer.push_transaction(transaction, Instant::now());
 5467                            buffer.finalize_last_transaction();
 5468                        })
 5469                        .ok();
 5470                }
 5471                editor.update(cx, |editor, cx| {
 5472                    editor.refresh_document_highlights(cx);
 5473                })?;
 5474            }
 5475            Ok(())
 5476        }))
 5477    }
 5478
 5479    pub fn show_word_completions(
 5480        &mut self,
 5481        _: &ShowWordCompletions,
 5482        window: &mut Window,
 5483        cx: &mut Context<Self>,
 5484    ) {
 5485        self.open_or_update_completions_menu(
 5486            Some(CompletionsMenuSource::Words {
 5487                ignore_threshold: true,
 5488            }),
 5489            None,
 5490            window,
 5491            cx,
 5492        );
 5493    }
 5494
 5495    pub fn show_completions(
 5496        &mut self,
 5497        options: &ShowCompletions,
 5498        window: &mut Window,
 5499        cx: &mut Context<Self>,
 5500    ) {
 5501        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5502    }
 5503
 5504    fn open_or_update_completions_menu(
 5505        &mut self,
 5506        requested_source: Option<CompletionsMenuSource>,
 5507        trigger: Option<&str>,
 5508        window: &mut Window,
 5509        cx: &mut Context<Self>,
 5510    ) {
 5511        if self.pending_rename.is_some() {
 5512            return;
 5513        }
 5514
 5515        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5516
 5517        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5518        // inserted and selected. To handle that case, the start of the selection is used so that
 5519        // the menu starts with all choices.
 5520        let position = self
 5521            .selections
 5522            .newest_anchor()
 5523            .start
 5524            .bias_right(&multibuffer_snapshot);
 5525        if position.diff_base_anchor.is_some() {
 5526            return;
 5527        }
 5528        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5529        let Some(buffer) = buffer_position
 5530            .buffer_id
 5531            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5532        else {
 5533            return;
 5534        };
 5535        let buffer_snapshot = buffer.read(cx).snapshot();
 5536
 5537        let query: Option<Arc<String>> =
 5538            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5539                .map(|query| query.into());
 5540
 5541        drop(multibuffer_snapshot);
 5542
 5543        // Hide the current completions menu when query is empty. Without this, cached
 5544        // completions from before the trigger char may be reused (#32774).
 5545        if query.is_none() {
 5546            let menu_is_open = matches!(
 5547                self.context_menu.borrow().as_ref(),
 5548                Some(CodeContextMenu::Completions(_))
 5549            );
 5550            if menu_is_open {
 5551                self.hide_context_menu(window, cx);
 5552            }
 5553        }
 5554
 5555        let mut ignore_word_threshold = false;
 5556        let provider = match requested_source {
 5557            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5558            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5559                ignore_word_threshold = ignore_threshold;
 5560                None
 5561            }
 5562            Some(CompletionsMenuSource::SnippetChoices) => {
 5563                log::error!("bug: SnippetChoices requested_source is not handled");
 5564                None
 5565            }
 5566        };
 5567
 5568        let sort_completions = provider
 5569            .as_ref()
 5570            .is_some_and(|provider| provider.sort_completions());
 5571
 5572        let filter_completions = provider
 5573            .as_ref()
 5574            .is_none_or(|provider| provider.filter_completions());
 5575
 5576        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5577            if filter_completions {
 5578                menu.filter(query.clone(), provider.clone(), window, cx);
 5579            }
 5580            // When `is_incomplete` is false, no need to re-query completions when the current query
 5581            // is a suffix of the initial query.
 5582            if !menu.is_incomplete {
 5583                // If the new query is a suffix of the old query (typing more characters) and
 5584                // the previous result was complete, the existing completions can be filtered.
 5585                //
 5586                // Note that this is always true for snippet completions.
 5587                let query_matches = match (&menu.initial_query, &query) {
 5588                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5589                    (None, _) => true,
 5590                    _ => false,
 5591                };
 5592                if query_matches {
 5593                    let position_matches = if menu.initial_position == position {
 5594                        true
 5595                    } else {
 5596                        let snapshot = self.buffer.read(cx).read(cx);
 5597                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5598                    };
 5599                    if position_matches {
 5600                        return;
 5601                    }
 5602                }
 5603            }
 5604        };
 5605
 5606        let trigger_kind = match trigger {
 5607            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5608                CompletionTriggerKind::TRIGGER_CHARACTER
 5609            }
 5610            _ => CompletionTriggerKind::INVOKED,
 5611        };
 5612        let completion_context = CompletionContext {
 5613            trigger_character: trigger.and_then(|trigger| {
 5614                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5615                    Some(String::from(trigger))
 5616                } else {
 5617                    None
 5618                }
 5619            }),
 5620            trigger_kind,
 5621        };
 5622
 5623        let Anchor {
 5624            excerpt_id: buffer_excerpt_id,
 5625            text_anchor: buffer_position,
 5626            ..
 5627        } = buffer_position;
 5628
 5629        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5630            buffer_snapshot.surrounding_word(buffer_position, None)
 5631        {
 5632            let word_to_exclude = buffer_snapshot
 5633                .text_for_range(word_range.clone())
 5634                .collect::<String>();
 5635            (
 5636                buffer_snapshot.anchor_before(word_range.start)
 5637                    ..buffer_snapshot.anchor_after(buffer_position),
 5638                Some(word_to_exclude),
 5639            )
 5640        } else {
 5641            (buffer_position..buffer_position, None)
 5642        };
 5643
 5644        let language = buffer_snapshot
 5645            .language_at(buffer_position)
 5646            .map(|language| language.name());
 5647
 5648        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5649            .completions
 5650            .clone();
 5651
 5652        let show_completion_documentation = buffer_snapshot
 5653            .settings_at(buffer_position, cx)
 5654            .show_completion_documentation;
 5655
 5656        // The document can be large, so stay in reasonable bounds when searching for words,
 5657        // otherwise completion pop-up might be slow to appear.
 5658        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5659        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5660        let min_word_search = buffer_snapshot.clip_point(
 5661            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5662            Bias::Left,
 5663        );
 5664        let max_word_search = buffer_snapshot.clip_point(
 5665            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5666            Bias::Right,
 5667        );
 5668        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5669            ..buffer_snapshot.point_to_offset(max_word_search);
 5670
 5671        let skip_digits = query
 5672            .as_ref()
 5673            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5674
 5675        let omit_word_completions = !self.word_completions_enabled
 5676            || (!ignore_word_threshold
 5677                && match &query {
 5678                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5679                    None => completion_settings.words_min_length != 0,
 5680                });
 5681
 5682        let (mut words, provider_responses) = match &provider {
 5683            Some(provider) => {
 5684                let provider_responses = provider.completions(
 5685                    buffer_excerpt_id,
 5686                    &buffer,
 5687                    buffer_position,
 5688                    completion_context,
 5689                    window,
 5690                    cx,
 5691                );
 5692
 5693                let words = match (omit_word_completions, completion_settings.words) {
 5694                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5695                        Task::ready(BTreeMap::default())
 5696                    }
 5697                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5698                        .background_spawn(async move {
 5699                            buffer_snapshot.words_in_range(WordsQuery {
 5700                                fuzzy_contents: None,
 5701                                range: word_search_range,
 5702                                skip_digits,
 5703                            })
 5704                        }),
 5705                };
 5706
 5707                (words, provider_responses)
 5708            }
 5709            None => {
 5710                let words = if omit_word_completions {
 5711                    Task::ready(BTreeMap::default())
 5712                } else {
 5713                    cx.background_spawn(async move {
 5714                        buffer_snapshot.words_in_range(WordsQuery {
 5715                            fuzzy_contents: None,
 5716                            range: word_search_range,
 5717                            skip_digits,
 5718                        })
 5719                    })
 5720                };
 5721                (words, Task::ready(Ok(Vec::new())))
 5722            }
 5723        };
 5724
 5725        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5726
 5727        let id = post_inc(&mut self.next_completion_id);
 5728        let task = cx.spawn_in(window, async move |editor, cx| {
 5729            let Ok(()) = editor.update(cx, |this, _| {
 5730                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5731            }) else {
 5732                return;
 5733            };
 5734
 5735            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5736            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5737            let mut completions = Vec::new();
 5738            let mut is_incomplete = false;
 5739            let mut display_options: Option<CompletionDisplayOptions> = None;
 5740            if let Some(provider_responses) = provider_responses.await.log_err()
 5741                && !provider_responses.is_empty()
 5742            {
 5743                for response in provider_responses {
 5744                    completions.extend(response.completions);
 5745                    is_incomplete = is_incomplete || response.is_incomplete;
 5746                    match display_options.as_mut() {
 5747                        None => {
 5748                            display_options = Some(response.display_options);
 5749                        }
 5750                        Some(options) => options.merge(&response.display_options),
 5751                    }
 5752                }
 5753                if completion_settings.words == WordsCompletionMode::Fallback {
 5754                    words = Task::ready(BTreeMap::default());
 5755                }
 5756            }
 5757            let display_options = display_options.unwrap_or_default();
 5758
 5759            let mut words = words.await;
 5760            if let Some(word_to_exclude) = &word_to_exclude {
 5761                words.remove(word_to_exclude);
 5762            }
 5763            for lsp_completion in &completions {
 5764                words.remove(&lsp_completion.new_text);
 5765            }
 5766            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5767                replace_range: word_replace_range.clone(),
 5768                new_text: word.clone(),
 5769                label: CodeLabel::plain(word, None),
 5770                icon_path: None,
 5771                documentation: None,
 5772                source: CompletionSource::BufferWord {
 5773                    word_range,
 5774                    resolved: false,
 5775                },
 5776                insert_text_mode: Some(InsertTextMode::AS_IS),
 5777                confirm: None,
 5778            }));
 5779
 5780            let menu = if completions.is_empty() {
 5781                None
 5782            } else {
 5783                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5784                    let languages = editor
 5785                        .workspace
 5786                        .as_ref()
 5787                        .and_then(|(workspace, _)| workspace.upgrade())
 5788                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5789                    let menu = CompletionsMenu::new(
 5790                        id,
 5791                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5792                        sort_completions,
 5793                        show_completion_documentation,
 5794                        position,
 5795                        query.clone(),
 5796                        is_incomplete,
 5797                        buffer.clone(),
 5798                        completions.into(),
 5799                        display_options,
 5800                        snippet_sort_order,
 5801                        languages,
 5802                        language,
 5803                        cx,
 5804                    );
 5805
 5806                    let query = if filter_completions { query } else { None };
 5807                    let matches_task = if let Some(query) = query {
 5808                        menu.do_async_filtering(query, cx)
 5809                    } else {
 5810                        Task::ready(menu.unfiltered_matches())
 5811                    };
 5812                    (menu, matches_task)
 5813                }) else {
 5814                    return;
 5815                };
 5816
 5817                let matches = matches_task.await;
 5818
 5819                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5820                    // Newer menu already set, so exit.
 5821                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5822                        editor.context_menu.borrow().as_ref()
 5823                        && prev_menu.id > id
 5824                    {
 5825                        return;
 5826                    };
 5827
 5828                    // Only valid to take prev_menu because it the new menu is immediately set
 5829                    // below, or the menu is hidden.
 5830                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5831                        editor.context_menu.borrow_mut().take()
 5832                    {
 5833                        let position_matches =
 5834                            if prev_menu.initial_position == menu.initial_position {
 5835                                true
 5836                            } else {
 5837                                let snapshot = editor.buffer.read(cx).read(cx);
 5838                                prev_menu.initial_position.to_offset(&snapshot)
 5839                                    == menu.initial_position.to_offset(&snapshot)
 5840                            };
 5841                        if position_matches {
 5842                            // Preserve markdown cache before `set_filter_results` because it will
 5843                            // try to populate the documentation cache.
 5844                            menu.preserve_markdown_cache(prev_menu);
 5845                        }
 5846                    };
 5847
 5848                    menu.set_filter_results(matches, provider, window, cx);
 5849                }) else {
 5850                    return;
 5851                };
 5852
 5853                menu.visible().then_some(menu)
 5854            };
 5855
 5856            editor
 5857                .update_in(cx, |editor, window, cx| {
 5858                    if editor.focus_handle.is_focused(window)
 5859                        && let Some(menu) = menu
 5860                    {
 5861                        *editor.context_menu.borrow_mut() =
 5862                            Some(CodeContextMenu::Completions(menu));
 5863
 5864                        crate::hover_popover::hide_hover(editor, cx);
 5865                        if editor.show_edit_predictions_in_menu() {
 5866                            editor.update_visible_edit_prediction(window, cx);
 5867                        } else {
 5868                            editor.discard_edit_prediction(false, cx);
 5869                        }
 5870
 5871                        cx.notify();
 5872                        return;
 5873                    }
 5874
 5875                    if editor.completion_tasks.len() <= 1 {
 5876                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5877                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5878                        // If it was already hidden and we don't show edit predictions in the menu,
 5879                        // we should also show the edit prediction when available.
 5880                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5881                            editor.update_visible_edit_prediction(window, cx);
 5882                        }
 5883                    }
 5884                })
 5885                .ok();
 5886        });
 5887
 5888        self.completion_tasks.push((id, task));
 5889    }
 5890
 5891    #[cfg(feature = "test-support")]
 5892    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5893        let menu = self.context_menu.borrow();
 5894        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5895            let completions = menu.completions.borrow();
 5896            Some(completions.to_vec())
 5897        } else {
 5898            None
 5899        }
 5900    }
 5901
 5902    pub fn with_completions_menu_matching_id<R>(
 5903        &self,
 5904        id: CompletionId,
 5905        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5906    ) -> R {
 5907        let mut context_menu = self.context_menu.borrow_mut();
 5908        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5909            return f(None);
 5910        };
 5911        if completions_menu.id != id {
 5912            return f(None);
 5913        }
 5914        f(Some(completions_menu))
 5915    }
 5916
 5917    pub fn confirm_completion(
 5918        &mut self,
 5919        action: &ConfirmCompletion,
 5920        window: &mut Window,
 5921        cx: &mut Context<Self>,
 5922    ) -> Option<Task<Result<()>>> {
 5923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5924        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5925    }
 5926
 5927    pub fn confirm_completion_insert(
 5928        &mut self,
 5929        _: &ConfirmCompletionInsert,
 5930        window: &mut Window,
 5931        cx: &mut Context<Self>,
 5932    ) -> Option<Task<Result<()>>> {
 5933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5934        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5935    }
 5936
 5937    pub fn confirm_completion_replace(
 5938        &mut self,
 5939        _: &ConfirmCompletionReplace,
 5940        window: &mut Window,
 5941        cx: &mut Context<Self>,
 5942    ) -> Option<Task<Result<()>>> {
 5943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5944        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5945    }
 5946
 5947    pub fn compose_completion(
 5948        &mut self,
 5949        action: &ComposeCompletion,
 5950        window: &mut Window,
 5951        cx: &mut Context<Self>,
 5952    ) -> Option<Task<Result<()>>> {
 5953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5954        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5955    }
 5956
 5957    fn do_completion(
 5958        &mut self,
 5959        item_ix: Option<usize>,
 5960        intent: CompletionIntent,
 5961        window: &mut Window,
 5962        cx: &mut Context<Editor>,
 5963    ) -> Option<Task<Result<()>>> {
 5964        use language::ToOffset as _;
 5965
 5966        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5967        else {
 5968            return None;
 5969        };
 5970
 5971        let candidate_id = {
 5972            let entries = completions_menu.entries.borrow();
 5973            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5974            if self.show_edit_predictions_in_menu() {
 5975                self.discard_edit_prediction(true, cx);
 5976            }
 5977            mat.candidate_id
 5978        };
 5979
 5980        let completion = completions_menu
 5981            .completions
 5982            .borrow()
 5983            .get(candidate_id)?
 5984            .clone();
 5985        cx.stop_propagation();
 5986
 5987        let buffer_handle = completions_menu.buffer.clone();
 5988
 5989        let CompletionEdit {
 5990            new_text,
 5991            snippet,
 5992            replace_range,
 5993        } = process_completion_for_edit(
 5994            &completion,
 5995            intent,
 5996            &buffer_handle,
 5997            &completions_menu.initial_position.text_anchor,
 5998            cx,
 5999        );
 6000
 6001        let buffer = buffer_handle.read(cx);
 6002        let snapshot = self.buffer.read(cx).snapshot(cx);
 6003        let newest_anchor = self.selections.newest_anchor();
 6004        let replace_range_multibuffer = {
 6005            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6006            let multibuffer_anchor = snapshot
 6007                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 6008                .unwrap()
 6009                ..snapshot
 6010                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 6011                    .unwrap();
 6012            multibuffer_anchor.start.to_offset(&snapshot)
 6013                ..multibuffer_anchor.end.to_offset(&snapshot)
 6014        };
 6015        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6016            return None;
 6017        }
 6018
 6019        let old_text = buffer
 6020            .text_for_range(replace_range.clone())
 6021            .collect::<String>();
 6022        let lookbehind = newest_anchor
 6023            .start
 6024            .text_anchor
 6025            .to_offset(buffer)
 6026            .saturating_sub(replace_range.start);
 6027        let lookahead = replace_range
 6028            .end
 6029            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6030        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6031        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6032
 6033        let selections = self.selections.all::<usize>(cx);
 6034        let mut ranges = Vec::new();
 6035        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6036
 6037        for selection in &selections {
 6038            let range = if selection.id == newest_anchor.id {
 6039                replace_range_multibuffer.clone()
 6040            } else {
 6041                let mut range = selection.range();
 6042
 6043                // if prefix is present, don't duplicate it
 6044                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6045                    range.start = range.start.saturating_sub(lookbehind);
 6046
 6047                    // if suffix is also present, mimic the newest cursor and replace it
 6048                    if selection.id != newest_anchor.id
 6049                        && snapshot.contains_str_at(range.end, suffix)
 6050                    {
 6051                        range.end += lookahead;
 6052                    }
 6053                }
 6054                range
 6055            };
 6056
 6057            ranges.push(range.clone());
 6058
 6059            if !self.linked_edit_ranges.is_empty() {
 6060                let start_anchor = snapshot.anchor_before(range.start);
 6061                let end_anchor = snapshot.anchor_after(range.end);
 6062                if let Some(ranges) = self
 6063                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6064                {
 6065                    for (buffer, edits) in ranges {
 6066                        linked_edits
 6067                            .entry(buffer.clone())
 6068                            .or_default()
 6069                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6070                    }
 6071                }
 6072            }
 6073        }
 6074
 6075        let common_prefix_len = old_text
 6076            .chars()
 6077            .zip(new_text.chars())
 6078            .take_while(|(a, b)| a == b)
 6079            .map(|(a, _)| a.len_utf8())
 6080            .sum::<usize>();
 6081
 6082        cx.emit(EditorEvent::InputHandled {
 6083            utf16_range_to_replace: None,
 6084            text: new_text[common_prefix_len..].into(),
 6085        });
 6086
 6087        self.transact(window, cx, |editor, window, cx| {
 6088            if let Some(mut snippet) = snippet {
 6089                snippet.text = new_text.to_string();
 6090                editor
 6091                    .insert_snippet(&ranges, snippet, window, cx)
 6092                    .log_err();
 6093            } else {
 6094                editor.buffer.update(cx, |multi_buffer, cx| {
 6095                    let auto_indent = match completion.insert_text_mode {
 6096                        Some(InsertTextMode::AS_IS) => None,
 6097                        _ => editor.autoindent_mode.clone(),
 6098                    };
 6099                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6100                    multi_buffer.edit(edits, auto_indent, cx);
 6101                });
 6102            }
 6103            for (buffer, edits) in linked_edits {
 6104                buffer.update(cx, |buffer, cx| {
 6105                    let snapshot = buffer.snapshot();
 6106                    let edits = edits
 6107                        .into_iter()
 6108                        .map(|(range, text)| {
 6109                            use text::ToPoint as TP;
 6110                            let end_point = TP::to_point(&range.end, &snapshot);
 6111                            let start_point = TP::to_point(&range.start, &snapshot);
 6112                            (start_point..end_point, text)
 6113                        })
 6114                        .sorted_by_key(|(range, _)| range.start);
 6115                    buffer.edit(edits, None, cx);
 6116                })
 6117            }
 6118
 6119            editor.refresh_edit_prediction(true, false, window, cx);
 6120        });
 6121        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6122
 6123        let show_new_completions_on_confirm = completion
 6124            .confirm
 6125            .as_ref()
 6126            .is_some_and(|confirm| confirm(intent, window, cx));
 6127        if show_new_completions_on_confirm {
 6128            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6129        }
 6130
 6131        let provider = self.completion_provider.as_ref()?;
 6132        drop(completion);
 6133        let apply_edits = provider.apply_additional_edits_for_completion(
 6134            buffer_handle,
 6135            completions_menu.completions.clone(),
 6136            candidate_id,
 6137            true,
 6138            cx,
 6139        );
 6140
 6141        let editor_settings = EditorSettings::get_global(cx);
 6142        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6143            // After the code completion is finished, users often want to know what signatures are needed.
 6144            // so we should automatically call signature_help
 6145            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6146        }
 6147
 6148        Some(cx.foreground_executor().spawn(async move {
 6149            apply_edits.await?;
 6150            Ok(())
 6151        }))
 6152    }
 6153
 6154    pub fn toggle_code_actions(
 6155        &mut self,
 6156        action: &ToggleCodeActions,
 6157        window: &mut Window,
 6158        cx: &mut Context<Self>,
 6159    ) {
 6160        let quick_launch = action.quick_launch;
 6161        let mut context_menu = self.context_menu.borrow_mut();
 6162        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6163            if code_actions.deployed_from == action.deployed_from {
 6164                // Toggle if we're selecting the same one
 6165                *context_menu = None;
 6166                cx.notify();
 6167                return;
 6168            } else {
 6169                // Otherwise, clear it and start a new one
 6170                *context_menu = None;
 6171                cx.notify();
 6172            }
 6173        }
 6174        drop(context_menu);
 6175        let snapshot = self.snapshot(window, cx);
 6176        let deployed_from = action.deployed_from.clone();
 6177        let action = action.clone();
 6178        self.completion_tasks.clear();
 6179        self.discard_edit_prediction(false, cx);
 6180
 6181        let multibuffer_point = match &action.deployed_from {
 6182            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6183                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6184            }
 6185            _ => self.selections.newest::<Point>(cx).head(),
 6186        };
 6187        let Some((buffer, buffer_row)) = snapshot
 6188            .buffer_snapshot()
 6189            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6190            .and_then(|(buffer_snapshot, range)| {
 6191                self.buffer()
 6192                    .read(cx)
 6193                    .buffer(buffer_snapshot.remote_id())
 6194                    .map(|buffer| (buffer, range.start.row))
 6195            })
 6196        else {
 6197            return;
 6198        };
 6199        let buffer_id = buffer.read(cx).remote_id();
 6200        let tasks = self
 6201            .tasks
 6202            .get(&(buffer_id, buffer_row))
 6203            .map(|t| Arc::new(t.to_owned()));
 6204
 6205        if !self.focus_handle.is_focused(window) {
 6206            return;
 6207        }
 6208        let project = self.project.clone();
 6209
 6210        let code_actions_task = match deployed_from {
 6211            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6212            _ => self.code_actions(buffer_row, window, cx),
 6213        };
 6214
 6215        let runnable_task = match deployed_from {
 6216            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6217            _ => {
 6218                let mut task_context_task = Task::ready(None);
 6219                if let Some(tasks) = &tasks
 6220                    && let Some(project) = project
 6221                {
 6222                    task_context_task =
 6223                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6224                }
 6225
 6226                cx.spawn_in(window, {
 6227                    let buffer = buffer.clone();
 6228                    async move |editor, cx| {
 6229                        let task_context = task_context_task.await;
 6230
 6231                        let resolved_tasks =
 6232                            tasks
 6233                                .zip(task_context.clone())
 6234                                .map(|(tasks, task_context)| ResolvedTasks {
 6235                                    templates: tasks.resolve(&task_context).collect(),
 6236                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6237                                        multibuffer_point.row,
 6238                                        tasks.column,
 6239                                    )),
 6240                                });
 6241                        let debug_scenarios = editor
 6242                            .update(cx, |editor, cx| {
 6243                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6244                            })?
 6245                            .await;
 6246                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6247                    }
 6248                })
 6249            }
 6250        };
 6251
 6252        cx.spawn_in(window, async move |editor, cx| {
 6253            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6254            let code_actions = code_actions_task.await;
 6255            let spawn_straight_away = quick_launch
 6256                && resolved_tasks
 6257                    .as_ref()
 6258                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6259                && code_actions
 6260                    .as_ref()
 6261                    .is_none_or(|actions| actions.is_empty())
 6262                && debug_scenarios.is_empty();
 6263
 6264            editor.update_in(cx, |editor, window, cx| {
 6265                crate::hover_popover::hide_hover(editor, cx);
 6266                let actions = CodeActionContents::new(
 6267                    resolved_tasks,
 6268                    code_actions,
 6269                    debug_scenarios,
 6270                    task_context.unwrap_or_default(),
 6271                );
 6272
 6273                // Don't show the menu if there are no actions available
 6274                if actions.is_empty() {
 6275                    cx.notify();
 6276                    return Task::ready(Ok(()));
 6277                }
 6278
 6279                *editor.context_menu.borrow_mut() =
 6280                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6281                        buffer,
 6282                        actions,
 6283                        selected_item: Default::default(),
 6284                        scroll_handle: UniformListScrollHandle::default(),
 6285                        deployed_from,
 6286                    }));
 6287                cx.notify();
 6288                if spawn_straight_away
 6289                    && let Some(task) = editor.confirm_code_action(
 6290                        &ConfirmCodeAction { item_ix: Some(0) },
 6291                        window,
 6292                        cx,
 6293                    )
 6294                {
 6295                    return task;
 6296                }
 6297
 6298                Task::ready(Ok(()))
 6299            })
 6300        })
 6301        .detach_and_log_err(cx);
 6302    }
 6303
 6304    fn debug_scenarios(
 6305        &mut self,
 6306        resolved_tasks: &Option<ResolvedTasks>,
 6307        buffer: &Entity<Buffer>,
 6308        cx: &mut App,
 6309    ) -> Task<Vec<task::DebugScenario>> {
 6310        maybe!({
 6311            let project = self.project()?;
 6312            let dap_store = project.read(cx).dap_store();
 6313            let mut scenarios = vec![];
 6314            let resolved_tasks = resolved_tasks.as_ref()?;
 6315            let buffer = buffer.read(cx);
 6316            let language = buffer.language()?;
 6317            let file = buffer.file();
 6318            let debug_adapter = language_settings(language.name().into(), file, cx)
 6319                .debuggers
 6320                .first()
 6321                .map(SharedString::from)
 6322                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6323
 6324            dap_store.update(cx, |dap_store, cx| {
 6325                for (_, task) in &resolved_tasks.templates {
 6326                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6327                        task.original_task().clone(),
 6328                        debug_adapter.clone().into(),
 6329                        task.display_label().to_owned().into(),
 6330                        cx,
 6331                    );
 6332                    scenarios.push(maybe_scenario);
 6333                }
 6334            });
 6335            Some(cx.background_spawn(async move {
 6336                futures::future::join_all(scenarios)
 6337                    .await
 6338                    .into_iter()
 6339                    .flatten()
 6340                    .collect::<Vec<_>>()
 6341            }))
 6342        })
 6343        .unwrap_or_else(|| Task::ready(vec![]))
 6344    }
 6345
 6346    fn code_actions(
 6347        &mut self,
 6348        buffer_row: u32,
 6349        window: &mut Window,
 6350        cx: &mut Context<Self>,
 6351    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6352        let mut task = self.code_actions_task.take();
 6353        cx.spawn_in(window, async move |editor, cx| {
 6354            while let Some(prev_task) = task {
 6355                prev_task.await.log_err();
 6356                task = editor
 6357                    .update(cx, |this, _| this.code_actions_task.take())
 6358                    .ok()?;
 6359            }
 6360
 6361            editor
 6362                .update(cx, |editor, cx| {
 6363                    editor
 6364                        .available_code_actions
 6365                        .clone()
 6366                        .and_then(|(location, code_actions)| {
 6367                            let snapshot = location.buffer.read(cx).snapshot();
 6368                            let point_range = location.range.to_point(&snapshot);
 6369                            let point_range = point_range.start.row..=point_range.end.row;
 6370                            if point_range.contains(&buffer_row) {
 6371                                Some(code_actions)
 6372                            } else {
 6373                                None
 6374                            }
 6375                        })
 6376                })
 6377                .ok()
 6378                .flatten()
 6379        })
 6380    }
 6381
 6382    pub fn confirm_code_action(
 6383        &mut self,
 6384        action: &ConfirmCodeAction,
 6385        window: &mut Window,
 6386        cx: &mut Context<Self>,
 6387    ) -> Option<Task<Result<()>>> {
 6388        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6389
 6390        let actions_menu =
 6391            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6392                menu
 6393            } else {
 6394                return None;
 6395            };
 6396
 6397        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6398        let action = actions_menu.actions.get(action_ix)?;
 6399        let title = action.label();
 6400        let buffer = actions_menu.buffer;
 6401        let workspace = self.workspace()?;
 6402
 6403        match action {
 6404            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6405                workspace.update(cx, |workspace, cx| {
 6406                    workspace.schedule_resolved_task(
 6407                        task_source_kind,
 6408                        resolved_task,
 6409                        false,
 6410                        window,
 6411                        cx,
 6412                    );
 6413
 6414                    Some(Task::ready(Ok(())))
 6415                })
 6416            }
 6417            CodeActionsItem::CodeAction {
 6418                excerpt_id,
 6419                action,
 6420                provider,
 6421            } => {
 6422                let apply_code_action =
 6423                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6424                let workspace = workspace.downgrade();
 6425                Some(cx.spawn_in(window, async move |editor, cx| {
 6426                    let project_transaction = apply_code_action.await?;
 6427                    Self::open_project_transaction(
 6428                        &editor,
 6429                        workspace,
 6430                        project_transaction,
 6431                        title,
 6432                        cx,
 6433                    )
 6434                    .await
 6435                }))
 6436            }
 6437            CodeActionsItem::DebugScenario(scenario) => {
 6438                let context = actions_menu.actions.context;
 6439
 6440                workspace.update(cx, |workspace, cx| {
 6441                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6442                    workspace.start_debug_session(
 6443                        scenario,
 6444                        context,
 6445                        Some(buffer),
 6446                        None,
 6447                        window,
 6448                        cx,
 6449                    );
 6450                });
 6451                Some(Task::ready(Ok(())))
 6452            }
 6453        }
 6454    }
 6455
 6456    pub async fn open_project_transaction(
 6457        editor: &WeakEntity<Editor>,
 6458        workspace: WeakEntity<Workspace>,
 6459        transaction: ProjectTransaction,
 6460        title: String,
 6461        cx: &mut AsyncWindowContext,
 6462    ) -> Result<()> {
 6463        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6464        cx.update(|_, cx| {
 6465            entries.sort_unstable_by_key(|(buffer, _)| {
 6466                buffer.read(cx).file().map(|f| f.path().clone())
 6467            });
 6468        })?;
 6469        if entries.is_empty() {
 6470            return Ok(());
 6471        }
 6472
 6473        // If the project transaction's edits are all contained within this editor, then
 6474        // avoid opening a new editor to display them.
 6475
 6476        if let [(buffer, transaction)] = &*entries {
 6477            let excerpt = editor.update(cx, |editor, cx| {
 6478                editor
 6479                    .buffer()
 6480                    .read(cx)
 6481                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6482            })?;
 6483            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6484                && excerpted_buffer == *buffer
 6485            {
 6486                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6487                    let excerpt_range = excerpt_range.to_offset(buffer);
 6488                    buffer
 6489                        .edited_ranges_for_transaction::<usize>(transaction)
 6490                        .all(|range| {
 6491                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6492                        })
 6493                })?;
 6494
 6495                if all_edits_within_excerpt {
 6496                    return Ok(());
 6497                }
 6498            }
 6499        }
 6500
 6501        let mut ranges_to_highlight = Vec::new();
 6502        let excerpt_buffer = cx.new(|cx| {
 6503            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6504            for (buffer_handle, transaction) in &entries {
 6505                let edited_ranges = buffer_handle
 6506                    .read(cx)
 6507                    .edited_ranges_for_transaction::<Point>(transaction)
 6508                    .collect::<Vec<_>>();
 6509                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6510                    PathKey::for_buffer(buffer_handle, cx),
 6511                    buffer_handle.clone(),
 6512                    edited_ranges,
 6513                    multibuffer_context_lines(cx),
 6514                    cx,
 6515                );
 6516
 6517                ranges_to_highlight.extend(ranges);
 6518            }
 6519            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6520            multibuffer
 6521        })?;
 6522
 6523        workspace.update_in(cx, |workspace, window, cx| {
 6524            let project = workspace.project().clone();
 6525            let editor =
 6526                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6527            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6528            editor.update(cx, |editor, cx| {
 6529                editor.highlight_background::<Self>(
 6530                    &ranges_to_highlight,
 6531                    |theme| theme.colors().editor_highlighted_line_background,
 6532                    cx,
 6533                );
 6534            });
 6535        })?;
 6536
 6537        Ok(())
 6538    }
 6539
 6540    pub fn clear_code_action_providers(&mut self) {
 6541        self.code_action_providers.clear();
 6542        self.available_code_actions.take();
 6543    }
 6544
 6545    pub fn add_code_action_provider(
 6546        &mut self,
 6547        provider: Rc<dyn CodeActionProvider>,
 6548        window: &mut Window,
 6549        cx: &mut Context<Self>,
 6550    ) {
 6551        if self
 6552            .code_action_providers
 6553            .iter()
 6554            .any(|existing_provider| existing_provider.id() == provider.id())
 6555        {
 6556            return;
 6557        }
 6558
 6559        self.code_action_providers.push(provider);
 6560        self.refresh_code_actions(window, cx);
 6561    }
 6562
 6563    pub fn remove_code_action_provider(
 6564        &mut self,
 6565        id: Arc<str>,
 6566        window: &mut Window,
 6567        cx: &mut Context<Self>,
 6568    ) {
 6569        self.code_action_providers
 6570            .retain(|provider| provider.id() != id);
 6571        self.refresh_code_actions(window, cx);
 6572    }
 6573
 6574    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6575        !self.code_action_providers.is_empty()
 6576            && EditorSettings::get_global(cx).toolbar.code_actions
 6577    }
 6578
 6579    pub fn has_available_code_actions(&self) -> bool {
 6580        self.available_code_actions
 6581            .as_ref()
 6582            .is_some_and(|(_, actions)| !actions.is_empty())
 6583    }
 6584
 6585    fn render_inline_code_actions(
 6586        &self,
 6587        icon_size: ui::IconSize,
 6588        display_row: DisplayRow,
 6589        is_active: bool,
 6590        cx: &mut Context<Self>,
 6591    ) -> AnyElement {
 6592        let show_tooltip = !self.context_menu_visible();
 6593        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6594            .icon_size(icon_size)
 6595            .shape(ui::IconButtonShape::Square)
 6596            .icon_color(ui::Color::Hidden)
 6597            .toggle_state(is_active)
 6598            .when(show_tooltip, |this| {
 6599                this.tooltip({
 6600                    let focus_handle = self.focus_handle.clone();
 6601                    move |window, cx| {
 6602                        Tooltip::for_action_in(
 6603                            "Toggle Code Actions",
 6604                            &ToggleCodeActions {
 6605                                deployed_from: None,
 6606                                quick_launch: false,
 6607                            },
 6608                            &focus_handle,
 6609                            window,
 6610                            cx,
 6611                        )
 6612                    }
 6613                })
 6614            })
 6615            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6616                window.focus(&editor.focus_handle(cx));
 6617                editor.toggle_code_actions(
 6618                    &crate::actions::ToggleCodeActions {
 6619                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6620                            display_row,
 6621                        )),
 6622                        quick_launch: false,
 6623                    },
 6624                    window,
 6625                    cx,
 6626                );
 6627            }))
 6628            .into_any_element()
 6629    }
 6630
 6631    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6632        &self.context_menu
 6633    }
 6634
 6635    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6636        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6637            cx.background_executor()
 6638                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6639                .await;
 6640
 6641            let (start_buffer, start, _, end, newest_selection) = this
 6642                .update(cx, |this, cx| {
 6643                    let newest_selection = this.selections.newest_anchor().clone();
 6644                    if newest_selection.head().diff_base_anchor.is_some() {
 6645                        return None;
 6646                    }
 6647                    let newest_selection_adjusted = this.selections.newest_adjusted(cx);
 6648                    let buffer = this.buffer.read(cx);
 6649
 6650                    let (start_buffer, start) =
 6651                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6652                    let (end_buffer, end) =
 6653                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6654
 6655                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6656                })?
 6657                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6658                .context(
 6659                    "Expected selection to lie in a single buffer when refreshing code actions",
 6660                )?;
 6661            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6662                let providers = this.code_action_providers.clone();
 6663                let tasks = this
 6664                    .code_action_providers
 6665                    .iter()
 6666                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6667                    .collect::<Vec<_>>();
 6668                (providers, tasks)
 6669            })?;
 6670
 6671            let mut actions = Vec::new();
 6672            for (provider, provider_actions) in
 6673                providers.into_iter().zip(future::join_all(tasks).await)
 6674            {
 6675                if let Some(provider_actions) = provider_actions.log_err() {
 6676                    actions.extend(provider_actions.into_iter().map(|action| {
 6677                        AvailableCodeAction {
 6678                            excerpt_id: newest_selection.start.excerpt_id,
 6679                            action,
 6680                            provider: provider.clone(),
 6681                        }
 6682                    }));
 6683                }
 6684            }
 6685
 6686            this.update(cx, |this, cx| {
 6687                this.available_code_actions = if actions.is_empty() {
 6688                    None
 6689                } else {
 6690                    Some((
 6691                        Location {
 6692                            buffer: start_buffer,
 6693                            range: start..end,
 6694                        },
 6695                        actions.into(),
 6696                    ))
 6697                };
 6698                cx.notify();
 6699            })
 6700        }));
 6701    }
 6702
 6703    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6704        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6705            self.show_git_blame_inline = false;
 6706
 6707            self.show_git_blame_inline_delay_task =
 6708                Some(cx.spawn_in(window, async move |this, cx| {
 6709                    cx.background_executor().timer(delay).await;
 6710
 6711                    this.update(cx, |this, cx| {
 6712                        this.show_git_blame_inline = true;
 6713                        cx.notify();
 6714                    })
 6715                    .log_err();
 6716                }));
 6717        }
 6718    }
 6719
 6720    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6721        let snapshot = self.snapshot(window, cx);
 6722        let cursor = self.selections.newest::<Point>(cx).head();
 6723        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6724        else {
 6725            return;
 6726        };
 6727
 6728        let Some(blame) = self.blame.as_ref() else {
 6729            return;
 6730        };
 6731
 6732        let row_info = RowInfo {
 6733            buffer_id: Some(buffer.remote_id()),
 6734            buffer_row: Some(point.row),
 6735            ..Default::default()
 6736        };
 6737        let Some((buffer, blame_entry)) = blame
 6738            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6739            .flatten()
 6740        else {
 6741            return;
 6742        };
 6743
 6744        let anchor = self.selections.newest_anchor().head();
 6745        let position = self.to_pixel_point(anchor, &snapshot, window);
 6746        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6747            self.show_blame_popover(
 6748                buffer,
 6749                &blame_entry,
 6750                position + last_bounds.origin,
 6751                true,
 6752                cx,
 6753            );
 6754        };
 6755    }
 6756
 6757    fn show_blame_popover(
 6758        &mut self,
 6759        buffer: BufferId,
 6760        blame_entry: &BlameEntry,
 6761        position: gpui::Point<Pixels>,
 6762        ignore_timeout: bool,
 6763        cx: &mut Context<Self>,
 6764    ) {
 6765        if let Some(state) = &mut self.inline_blame_popover {
 6766            state.hide_task.take();
 6767        } else {
 6768            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6769            let blame_entry = blame_entry.clone();
 6770            let show_task = cx.spawn(async move |editor, cx| {
 6771                if !ignore_timeout {
 6772                    cx.background_executor()
 6773                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6774                        .await;
 6775                }
 6776                editor
 6777                    .update(cx, |editor, cx| {
 6778                        editor.inline_blame_popover_show_task.take();
 6779                        let Some(blame) = editor.blame.as_ref() else {
 6780                            return;
 6781                        };
 6782                        let blame = blame.read(cx);
 6783                        let details = blame.details_for_entry(buffer, &blame_entry);
 6784                        let markdown = cx.new(|cx| {
 6785                            Markdown::new(
 6786                                details
 6787                                    .as_ref()
 6788                                    .map(|message| message.message.clone())
 6789                                    .unwrap_or_default(),
 6790                                None,
 6791                                None,
 6792                                cx,
 6793                            )
 6794                        });
 6795                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6796                            position,
 6797                            hide_task: None,
 6798                            popover_bounds: None,
 6799                            popover_state: InlineBlamePopoverState {
 6800                                scroll_handle: ScrollHandle::new(),
 6801                                commit_message: details,
 6802                                markdown,
 6803                            },
 6804                            keyboard_grace: ignore_timeout,
 6805                        });
 6806                        cx.notify();
 6807                    })
 6808                    .ok();
 6809            });
 6810            self.inline_blame_popover_show_task = Some(show_task);
 6811        }
 6812    }
 6813
 6814    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6815        self.inline_blame_popover_show_task.take();
 6816        if let Some(state) = &mut self.inline_blame_popover {
 6817            let hide_task = cx.spawn(async move |editor, cx| {
 6818                cx.background_executor()
 6819                    .timer(std::time::Duration::from_millis(100))
 6820                    .await;
 6821                editor
 6822                    .update(cx, |editor, cx| {
 6823                        editor.inline_blame_popover.take();
 6824                        cx.notify();
 6825                    })
 6826                    .ok();
 6827            });
 6828            state.hide_task = Some(hide_task);
 6829        }
 6830    }
 6831
 6832    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6833        if self.pending_rename.is_some() {
 6834            return None;
 6835        }
 6836
 6837        let provider = self.semantics_provider.clone()?;
 6838        let buffer = self.buffer.read(cx);
 6839        let newest_selection = self.selections.newest_anchor().clone();
 6840        let cursor_position = newest_selection.head();
 6841        let (cursor_buffer, cursor_buffer_position) =
 6842            buffer.text_anchor_for_position(cursor_position, cx)?;
 6843        let (tail_buffer, tail_buffer_position) =
 6844            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6845        if cursor_buffer != tail_buffer {
 6846            return None;
 6847        }
 6848
 6849        let snapshot = cursor_buffer.read(cx).snapshot();
 6850        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6851        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6852        if start_word_range != end_word_range {
 6853            self.document_highlights_task.take();
 6854            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6855            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6856            return None;
 6857        }
 6858
 6859        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6860        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6861            cx.background_executor()
 6862                .timer(Duration::from_millis(debounce))
 6863                .await;
 6864
 6865            let highlights = if let Some(highlights) = cx
 6866                .update(|cx| {
 6867                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6868                })
 6869                .ok()
 6870                .flatten()
 6871            {
 6872                highlights.await.log_err()
 6873            } else {
 6874                None
 6875            };
 6876
 6877            if let Some(highlights) = highlights {
 6878                this.update(cx, |this, cx| {
 6879                    if this.pending_rename.is_some() {
 6880                        return;
 6881                    }
 6882
 6883                    let buffer = this.buffer.read(cx);
 6884                    if buffer
 6885                        .text_anchor_for_position(cursor_position, cx)
 6886                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6887                    {
 6888                        return;
 6889                    }
 6890
 6891                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6892                    let mut write_ranges = Vec::new();
 6893                    let mut read_ranges = Vec::new();
 6894                    for highlight in highlights {
 6895                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6896                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6897                        {
 6898                            let start = highlight
 6899                                .range
 6900                                .start
 6901                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6902                            let end = highlight
 6903                                .range
 6904                                .end
 6905                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6906                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6907                                continue;
 6908                            }
 6909
 6910                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6911                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6912                                write_ranges.push(range);
 6913                            } else {
 6914                                read_ranges.push(range);
 6915                            }
 6916                        }
 6917                    }
 6918
 6919                    this.highlight_background::<DocumentHighlightRead>(
 6920                        &read_ranges,
 6921                        |theme| theme.colors().editor_document_highlight_read_background,
 6922                        cx,
 6923                    );
 6924                    this.highlight_background::<DocumentHighlightWrite>(
 6925                        &write_ranges,
 6926                        |theme| theme.colors().editor_document_highlight_write_background,
 6927                        cx,
 6928                    );
 6929                    cx.notify();
 6930                })
 6931                .log_err();
 6932            }
 6933        }));
 6934        None
 6935    }
 6936
 6937    fn prepare_highlight_query_from_selection(
 6938        &mut self,
 6939        cx: &mut Context<Editor>,
 6940    ) -> Option<(String, Range<Anchor>)> {
 6941        if matches!(self.mode, EditorMode::SingleLine) {
 6942            return None;
 6943        }
 6944        if !EditorSettings::get_global(cx).selection_highlight {
 6945            return None;
 6946        }
 6947        if self.selections.count() != 1 || self.selections.line_mode() {
 6948            return None;
 6949        }
 6950        let selection = self.selections.newest_anchor();
 6951        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6952        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6953            ..selection.end.to_point(&multi_buffer_snapshot);
 6954        // If the selection spans multiple rows OR it is empty
 6955        if selection_point_range.start.row != selection_point_range.end.row
 6956            || selection_point_range.start.column == selection_point_range.end.column
 6957        {
 6958            return None;
 6959        }
 6960
 6961        let query = multi_buffer_snapshot
 6962            .text_for_range(selection.range())
 6963            .collect::<String>();
 6964        if query.trim().is_empty() {
 6965            return None;
 6966        }
 6967        Some((query, selection.range()))
 6968    }
 6969
 6970    fn update_selection_occurrence_highlights(
 6971        &mut self,
 6972        query_text: String,
 6973        query_range: Range<Anchor>,
 6974        multi_buffer_range_to_query: Range<Point>,
 6975        use_debounce: bool,
 6976        window: &mut Window,
 6977        cx: &mut Context<Editor>,
 6978    ) -> Task<()> {
 6979        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6980        cx.spawn_in(window, async move |editor, cx| {
 6981            if use_debounce {
 6982                cx.background_executor()
 6983                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6984                    .await;
 6985            }
 6986            let match_task = cx.background_spawn(async move {
 6987                let buffer_ranges = multi_buffer_snapshot
 6988                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6989                    .into_iter()
 6990                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6991                let mut match_ranges = Vec::new();
 6992                let Ok(regex) = project::search::SearchQuery::text(
 6993                    query_text.clone(),
 6994                    false,
 6995                    false,
 6996                    false,
 6997                    Default::default(),
 6998                    Default::default(),
 6999                    false,
 7000                    None,
 7001                ) else {
 7002                    return Vec::default();
 7003                };
 7004                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7005                    match_ranges.extend(
 7006                        regex
 7007                            .search(buffer_snapshot, Some(search_range.clone()))
 7008                            .await
 7009                            .into_iter()
 7010                            .filter_map(|match_range| {
 7011                                let match_start = buffer_snapshot
 7012                                    .anchor_after(search_range.start + match_range.start);
 7013                                let match_end = buffer_snapshot
 7014                                    .anchor_before(search_range.start + match_range.end);
 7015                                let match_anchor_range = Anchor::range_in_buffer(
 7016                                    excerpt_id,
 7017                                    buffer_snapshot.remote_id(),
 7018                                    match_start..match_end,
 7019                                );
 7020                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7021                            }),
 7022                    );
 7023                }
 7024                match_ranges
 7025            });
 7026            let match_ranges = match_task.await;
 7027            editor
 7028                .update_in(cx, |editor, _, cx| {
 7029                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7030                    if !match_ranges.is_empty() {
 7031                        editor.highlight_background::<SelectedTextHighlight>(
 7032                            &match_ranges,
 7033                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7034                            cx,
 7035                        )
 7036                    }
 7037                })
 7038                .log_err();
 7039        })
 7040    }
 7041
 7042    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7043        struct NewlineFold;
 7044        let type_id = std::any::TypeId::of::<NewlineFold>();
 7045        if !self.mode.is_single_line() {
 7046            return;
 7047        }
 7048        let snapshot = self.snapshot(window, cx);
 7049        if snapshot.buffer_snapshot().max_point().row == 0 {
 7050            return;
 7051        }
 7052        let task = cx.background_spawn(async move {
 7053            let new_newlines = snapshot
 7054                .buffer_chars_at(0)
 7055                .filter_map(|(c, i)| {
 7056                    if c == '\n' {
 7057                        Some(
 7058                            snapshot.buffer_snapshot().anchor_after(i)
 7059                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7060                        )
 7061                    } else {
 7062                        None
 7063                    }
 7064                })
 7065                .collect::<Vec<_>>();
 7066            let existing_newlines = snapshot
 7067                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7068                .filter_map(|fold| {
 7069                    if fold.placeholder.type_tag == Some(type_id) {
 7070                        Some(fold.range.start..fold.range.end)
 7071                    } else {
 7072                        None
 7073                    }
 7074                })
 7075                .collect::<Vec<_>>();
 7076
 7077            (new_newlines, existing_newlines)
 7078        });
 7079        self.folding_newlines = cx.spawn(async move |this, cx| {
 7080            let (new_newlines, existing_newlines) = task.await;
 7081            if new_newlines == existing_newlines {
 7082                return;
 7083            }
 7084            let placeholder = FoldPlaceholder {
 7085                render: Arc::new(move |_, _, cx| {
 7086                    div()
 7087                        .bg(cx.theme().status().hint_background)
 7088                        .border_b_1()
 7089                        .size_full()
 7090                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7091                        .border_color(cx.theme().status().hint)
 7092                        .child("\\n")
 7093                        .into_any()
 7094                }),
 7095                constrain_width: false,
 7096                merge_adjacent: false,
 7097                type_tag: Some(type_id),
 7098            };
 7099            let creases = new_newlines
 7100                .into_iter()
 7101                .map(|range| Crease::simple(range, placeholder.clone()))
 7102                .collect();
 7103            this.update(cx, |this, cx| {
 7104                this.display_map.update(cx, |display_map, cx| {
 7105                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7106                    display_map.fold(creases, cx);
 7107                });
 7108            })
 7109            .ok();
 7110        });
 7111    }
 7112
 7113    fn refresh_selected_text_highlights(
 7114        &mut self,
 7115        on_buffer_edit: bool,
 7116        window: &mut Window,
 7117        cx: &mut Context<Editor>,
 7118    ) {
 7119        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7120        else {
 7121            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7122            self.quick_selection_highlight_task.take();
 7123            self.debounced_selection_highlight_task.take();
 7124            return;
 7125        };
 7126        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7127        if on_buffer_edit
 7128            || self
 7129                .quick_selection_highlight_task
 7130                .as_ref()
 7131                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7132        {
 7133            let multi_buffer_visible_start = self
 7134                .scroll_manager
 7135                .anchor()
 7136                .anchor
 7137                .to_point(&multi_buffer_snapshot);
 7138            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7139                multi_buffer_visible_start
 7140                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7141                Bias::Left,
 7142            );
 7143            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7144            self.quick_selection_highlight_task = Some((
 7145                query_range.clone(),
 7146                self.update_selection_occurrence_highlights(
 7147                    query_text.clone(),
 7148                    query_range.clone(),
 7149                    multi_buffer_visible_range,
 7150                    false,
 7151                    window,
 7152                    cx,
 7153                ),
 7154            ));
 7155        }
 7156        if on_buffer_edit
 7157            || self
 7158                .debounced_selection_highlight_task
 7159                .as_ref()
 7160                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7161        {
 7162            let multi_buffer_start = multi_buffer_snapshot
 7163                .anchor_before(0)
 7164                .to_point(&multi_buffer_snapshot);
 7165            let multi_buffer_end = multi_buffer_snapshot
 7166                .anchor_after(multi_buffer_snapshot.len())
 7167                .to_point(&multi_buffer_snapshot);
 7168            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7169            self.debounced_selection_highlight_task = Some((
 7170                query_range.clone(),
 7171                self.update_selection_occurrence_highlights(
 7172                    query_text,
 7173                    query_range,
 7174                    multi_buffer_full_range,
 7175                    true,
 7176                    window,
 7177                    cx,
 7178                ),
 7179            ));
 7180        }
 7181    }
 7182
 7183    pub fn refresh_edit_prediction(
 7184        &mut self,
 7185        debounce: bool,
 7186        user_requested: bool,
 7187        window: &mut Window,
 7188        cx: &mut Context<Self>,
 7189    ) -> Option<()> {
 7190        if DisableAiSettings::get_global(cx).disable_ai {
 7191            return None;
 7192        }
 7193
 7194        let provider = self.edit_prediction_provider()?;
 7195        let cursor = self.selections.newest_anchor().head();
 7196        let (buffer, cursor_buffer_position) =
 7197            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7198
 7199        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7200            self.discard_edit_prediction(false, cx);
 7201            return None;
 7202        }
 7203
 7204        self.update_visible_edit_prediction(window, cx);
 7205
 7206        if !user_requested
 7207            && (!self.should_show_edit_predictions()
 7208                || !self.is_focused(window)
 7209                || buffer.read(cx).is_empty())
 7210        {
 7211            self.discard_edit_prediction(false, cx);
 7212            return None;
 7213        }
 7214
 7215        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7216        Some(())
 7217    }
 7218
 7219    fn show_edit_predictions_in_menu(&self) -> bool {
 7220        match self.edit_prediction_settings {
 7221            EditPredictionSettings::Disabled => false,
 7222            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7223        }
 7224    }
 7225
 7226    pub fn edit_predictions_enabled(&self) -> bool {
 7227        match self.edit_prediction_settings {
 7228            EditPredictionSettings::Disabled => false,
 7229            EditPredictionSettings::Enabled { .. } => true,
 7230        }
 7231    }
 7232
 7233    fn edit_prediction_requires_modifier(&self) -> bool {
 7234        match self.edit_prediction_settings {
 7235            EditPredictionSettings::Disabled => false,
 7236            EditPredictionSettings::Enabled {
 7237                preview_requires_modifier,
 7238                ..
 7239            } => preview_requires_modifier,
 7240        }
 7241    }
 7242
 7243    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7244        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7245            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7246            self.discard_edit_prediction(false, cx);
 7247        } else {
 7248            let selection = self.selections.newest_anchor();
 7249            let cursor = selection.head();
 7250
 7251            if let Some((buffer, cursor_buffer_position)) =
 7252                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7253            {
 7254                self.edit_prediction_settings =
 7255                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7256            }
 7257        }
 7258    }
 7259
 7260    fn edit_prediction_settings_at_position(
 7261        &self,
 7262        buffer: &Entity<Buffer>,
 7263        buffer_position: language::Anchor,
 7264        cx: &App,
 7265    ) -> EditPredictionSettings {
 7266        if !self.mode.is_full()
 7267            || !self.show_edit_predictions_override.unwrap_or(true)
 7268            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7269        {
 7270            return EditPredictionSettings::Disabled;
 7271        }
 7272
 7273        let buffer = buffer.read(cx);
 7274
 7275        let file = buffer.file();
 7276
 7277        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7278            return EditPredictionSettings::Disabled;
 7279        };
 7280
 7281        let by_provider = matches!(
 7282            self.menu_edit_predictions_policy,
 7283            MenuEditPredictionsPolicy::ByProvider
 7284        );
 7285
 7286        let show_in_menu = by_provider
 7287            && self
 7288                .edit_prediction_provider
 7289                .as_ref()
 7290                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7291
 7292        let preview_requires_modifier =
 7293            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7294
 7295        EditPredictionSettings::Enabled {
 7296            show_in_menu,
 7297            preview_requires_modifier,
 7298        }
 7299    }
 7300
 7301    fn should_show_edit_predictions(&self) -> bool {
 7302        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7303    }
 7304
 7305    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7306        matches!(
 7307            self.edit_prediction_preview,
 7308            EditPredictionPreview::Active { .. }
 7309        )
 7310    }
 7311
 7312    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7313        let cursor = self.selections.newest_anchor().head();
 7314        if let Some((buffer, cursor_position)) =
 7315            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7316        {
 7317            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7318        } else {
 7319            false
 7320        }
 7321    }
 7322
 7323    pub fn supports_minimap(&self, cx: &App) -> bool {
 7324        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7325    }
 7326
 7327    fn edit_predictions_enabled_in_buffer(
 7328        &self,
 7329        buffer: &Entity<Buffer>,
 7330        buffer_position: language::Anchor,
 7331        cx: &App,
 7332    ) -> bool {
 7333        maybe!({
 7334            if self.read_only(cx) {
 7335                return Some(false);
 7336            }
 7337            let provider = self.edit_prediction_provider()?;
 7338            if !provider.is_enabled(buffer, buffer_position, cx) {
 7339                return Some(false);
 7340            }
 7341            let buffer = buffer.read(cx);
 7342            let Some(file) = buffer.file() else {
 7343                return Some(true);
 7344            };
 7345            let settings = all_language_settings(Some(file), cx);
 7346            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7347        })
 7348        .unwrap_or(false)
 7349    }
 7350
 7351    fn cycle_edit_prediction(
 7352        &mut self,
 7353        direction: Direction,
 7354        window: &mut Window,
 7355        cx: &mut Context<Self>,
 7356    ) -> Option<()> {
 7357        let provider = self.edit_prediction_provider()?;
 7358        let cursor = self.selections.newest_anchor().head();
 7359        let (buffer, cursor_buffer_position) =
 7360            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7361        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7362            return None;
 7363        }
 7364
 7365        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7366        self.update_visible_edit_prediction(window, cx);
 7367
 7368        Some(())
 7369    }
 7370
 7371    pub fn show_edit_prediction(
 7372        &mut self,
 7373        _: &ShowEditPrediction,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) {
 7377        if !self.has_active_edit_prediction() {
 7378            self.refresh_edit_prediction(false, true, window, cx);
 7379            return;
 7380        }
 7381
 7382        self.update_visible_edit_prediction(window, cx);
 7383    }
 7384
 7385    pub fn display_cursor_names(
 7386        &mut self,
 7387        _: &DisplayCursorNames,
 7388        window: &mut Window,
 7389        cx: &mut Context<Self>,
 7390    ) {
 7391        self.show_cursor_names(window, cx);
 7392    }
 7393
 7394    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7395        self.show_cursor_names = true;
 7396        cx.notify();
 7397        cx.spawn_in(window, async move |this, cx| {
 7398            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7399            this.update(cx, |this, cx| {
 7400                this.show_cursor_names = false;
 7401                cx.notify()
 7402            })
 7403            .ok()
 7404        })
 7405        .detach();
 7406    }
 7407
 7408    pub fn next_edit_prediction(
 7409        &mut self,
 7410        _: &NextEditPrediction,
 7411        window: &mut Window,
 7412        cx: &mut Context<Self>,
 7413    ) {
 7414        if self.has_active_edit_prediction() {
 7415            self.cycle_edit_prediction(Direction::Next, window, cx);
 7416        } else {
 7417            let is_copilot_disabled = self
 7418                .refresh_edit_prediction(false, true, window, cx)
 7419                .is_none();
 7420            if is_copilot_disabled {
 7421                cx.propagate();
 7422            }
 7423        }
 7424    }
 7425
 7426    pub fn previous_edit_prediction(
 7427        &mut self,
 7428        _: &PreviousEditPrediction,
 7429        window: &mut Window,
 7430        cx: &mut Context<Self>,
 7431    ) {
 7432        if self.has_active_edit_prediction() {
 7433            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7434        } else {
 7435            let is_copilot_disabled = self
 7436                .refresh_edit_prediction(false, true, window, cx)
 7437                .is_none();
 7438            if is_copilot_disabled {
 7439                cx.propagate();
 7440            }
 7441        }
 7442    }
 7443
 7444    pub fn accept_edit_prediction(
 7445        &mut self,
 7446        _: &AcceptEditPrediction,
 7447        window: &mut Window,
 7448        cx: &mut Context<Self>,
 7449    ) {
 7450        if self.show_edit_predictions_in_menu() {
 7451            self.hide_context_menu(window, cx);
 7452        }
 7453
 7454        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7455            return;
 7456        };
 7457
 7458        match &active_edit_prediction.completion {
 7459            EditPrediction::MoveWithin { target, .. } => {
 7460                let target = *target;
 7461
 7462                if let Some(position_map) = &self.last_position_map {
 7463                    if position_map
 7464                        .visible_row_range
 7465                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7466                        || !self.edit_prediction_requires_modifier()
 7467                    {
 7468                        self.unfold_ranges(&[target..target], true, false, cx);
 7469                        // Note that this is also done in vim's handler of the Tab action.
 7470                        self.change_selections(
 7471                            SelectionEffects::scroll(Autoscroll::newest()),
 7472                            window,
 7473                            cx,
 7474                            |selections| {
 7475                                selections.select_anchor_ranges([target..target]);
 7476                            },
 7477                        );
 7478                        self.clear_row_highlights::<EditPredictionPreview>();
 7479
 7480                        self.edit_prediction_preview
 7481                            .set_previous_scroll_position(None);
 7482                    } else {
 7483                        self.edit_prediction_preview
 7484                            .set_previous_scroll_position(Some(
 7485                                position_map.snapshot.scroll_anchor,
 7486                            ));
 7487
 7488                        self.highlight_rows::<EditPredictionPreview>(
 7489                            target..target,
 7490                            cx.theme().colors().editor_highlighted_line_background,
 7491                            RowHighlightOptions {
 7492                                autoscroll: true,
 7493                                ..Default::default()
 7494                            },
 7495                            cx,
 7496                        );
 7497                        self.request_autoscroll(Autoscroll::fit(), cx);
 7498                    }
 7499                }
 7500            }
 7501            EditPrediction::MoveOutside { snapshot, target } => {
 7502                if let Some(workspace) = self.workspace() {
 7503                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7504                        .detach_and_log_err(cx);
 7505                }
 7506            }
 7507            EditPrediction::Edit { edits, .. } => {
 7508                self.report_edit_prediction_event(
 7509                    active_edit_prediction.completion_id.clone(),
 7510                    true,
 7511                    cx,
 7512                );
 7513
 7514                if let Some(provider) = self.edit_prediction_provider() {
 7515                    provider.accept(cx);
 7516                }
 7517
 7518                // Store the transaction ID and selections before applying the edit
 7519                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7520
 7521                let snapshot = self.buffer.read(cx).snapshot(cx);
 7522                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7523
 7524                self.buffer.update(cx, |buffer, cx| {
 7525                    buffer.edit(edits.iter().cloned(), None, cx)
 7526                });
 7527
 7528                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7529                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7530                });
 7531
 7532                let selections = self.selections.disjoint_anchors_arc();
 7533                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7534                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7535                    if has_new_transaction {
 7536                        self.selection_history
 7537                            .insert_transaction(transaction_id_now, selections);
 7538                    }
 7539                }
 7540
 7541                self.update_visible_edit_prediction(window, cx);
 7542                if self.active_edit_prediction.is_none() {
 7543                    self.refresh_edit_prediction(true, true, window, cx);
 7544                }
 7545
 7546                cx.notify();
 7547            }
 7548        }
 7549
 7550        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7551    }
 7552
 7553    pub fn accept_partial_edit_prediction(
 7554        &mut self,
 7555        _: &AcceptPartialEditPrediction,
 7556        window: &mut Window,
 7557        cx: &mut Context<Self>,
 7558    ) {
 7559        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7560            return;
 7561        };
 7562        if self.selections.count() != 1 {
 7563            return;
 7564        }
 7565
 7566        match &active_edit_prediction.completion {
 7567            EditPrediction::MoveWithin { target, .. } => {
 7568                let target = *target;
 7569                self.change_selections(
 7570                    SelectionEffects::scroll(Autoscroll::newest()),
 7571                    window,
 7572                    cx,
 7573                    |selections| {
 7574                        selections.select_anchor_ranges([target..target]);
 7575                    },
 7576                );
 7577            }
 7578            EditPrediction::MoveOutside { snapshot, target } => {
 7579                if let Some(workspace) = self.workspace() {
 7580                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7581                        .detach_and_log_err(cx);
 7582                }
 7583            }
 7584            EditPrediction::Edit { edits, .. } => {
 7585                self.report_edit_prediction_event(
 7586                    active_edit_prediction.completion_id.clone(),
 7587                    true,
 7588                    cx,
 7589                );
 7590
 7591                // Find an insertion that starts at the cursor position.
 7592                let snapshot = self.buffer.read(cx).snapshot(cx);
 7593                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7594                let insertion = edits.iter().find_map(|(range, text)| {
 7595                    let range = range.to_offset(&snapshot);
 7596                    if range.is_empty() && range.start == cursor_offset {
 7597                        Some(text)
 7598                    } else {
 7599                        None
 7600                    }
 7601                });
 7602
 7603                if let Some(text) = insertion {
 7604                    let mut partial_completion = text
 7605                        .chars()
 7606                        .by_ref()
 7607                        .take_while(|c| c.is_alphabetic())
 7608                        .collect::<String>();
 7609                    if partial_completion.is_empty() {
 7610                        partial_completion = text
 7611                            .chars()
 7612                            .by_ref()
 7613                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7614                            .collect::<String>();
 7615                    }
 7616
 7617                    cx.emit(EditorEvent::InputHandled {
 7618                        utf16_range_to_replace: None,
 7619                        text: partial_completion.clone().into(),
 7620                    });
 7621
 7622                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7623
 7624                    self.refresh_edit_prediction(true, true, window, cx);
 7625                    cx.notify();
 7626                } else {
 7627                    self.accept_edit_prediction(&Default::default(), window, cx);
 7628                }
 7629            }
 7630        }
 7631    }
 7632
 7633    fn discard_edit_prediction(
 7634        &mut self,
 7635        should_report_edit_prediction_event: bool,
 7636        cx: &mut Context<Self>,
 7637    ) -> bool {
 7638        if should_report_edit_prediction_event {
 7639            let completion_id = self
 7640                .active_edit_prediction
 7641                .as_ref()
 7642                .and_then(|active_completion| active_completion.completion_id.clone());
 7643
 7644            self.report_edit_prediction_event(completion_id, false, cx);
 7645        }
 7646
 7647        if let Some(provider) = self.edit_prediction_provider() {
 7648            provider.discard(cx);
 7649        }
 7650
 7651        self.take_active_edit_prediction(cx)
 7652    }
 7653
 7654    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7655        let Some(provider) = self.edit_prediction_provider() else {
 7656            return;
 7657        };
 7658
 7659        let Some((_, buffer, _)) = self
 7660            .buffer
 7661            .read(cx)
 7662            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7663        else {
 7664            return;
 7665        };
 7666
 7667        let extension = buffer
 7668            .read(cx)
 7669            .file()
 7670            .and_then(|file| Some(file.path().extension()?.to_string()));
 7671
 7672        let event_type = match accepted {
 7673            true => "Edit Prediction Accepted",
 7674            false => "Edit Prediction Discarded",
 7675        };
 7676        telemetry::event!(
 7677            event_type,
 7678            provider = provider.name(),
 7679            prediction_id = id,
 7680            suggestion_accepted = accepted,
 7681            file_extension = extension,
 7682        );
 7683    }
 7684
 7685    fn open_editor_at_anchor(
 7686        snapshot: &language::BufferSnapshot,
 7687        target: language::Anchor,
 7688        workspace: &Entity<Workspace>,
 7689        window: &mut Window,
 7690        cx: &mut App,
 7691    ) -> Task<Result<()>> {
 7692        workspace.update(cx, |workspace, cx| {
 7693            let path = snapshot.file().map(|file| file.full_path(cx));
 7694            let Some(path) =
 7695                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7696            else {
 7697                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7698            };
 7699            let target = text::ToPoint::to_point(&target, snapshot);
 7700            let item = workspace.open_path(path, None, true, window, cx);
 7701            window.spawn(cx, async move |cx| {
 7702                let Some(editor) = item.await?.downcast::<Editor>() else {
 7703                    return Ok(());
 7704                };
 7705                editor
 7706                    .update_in(cx, |editor, window, cx| {
 7707                        editor.go_to_singleton_buffer_point(target, window, cx);
 7708                    })
 7709                    .ok();
 7710                anyhow::Ok(())
 7711            })
 7712        })
 7713    }
 7714
 7715    pub fn has_active_edit_prediction(&self) -> bool {
 7716        self.active_edit_prediction.is_some()
 7717    }
 7718
 7719    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7720        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7721            return false;
 7722        };
 7723
 7724        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7725        self.clear_highlights::<EditPredictionHighlight>(cx);
 7726        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7727        true
 7728    }
 7729
 7730    /// Returns true when we're displaying the edit prediction popover below the cursor
 7731    /// like we are not previewing and the LSP autocomplete menu is visible
 7732    /// or we are in `when_holding_modifier` mode.
 7733    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7734        if self.edit_prediction_preview_is_active()
 7735            || !self.show_edit_predictions_in_menu()
 7736            || !self.edit_predictions_enabled()
 7737        {
 7738            return false;
 7739        }
 7740
 7741        if self.has_visible_completions_menu() {
 7742            return true;
 7743        }
 7744
 7745        has_completion && self.edit_prediction_requires_modifier()
 7746    }
 7747
 7748    fn handle_modifiers_changed(
 7749        &mut self,
 7750        modifiers: Modifiers,
 7751        position_map: &PositionMap,
 7752        window: &mut Window,
 7753        cx: &mut Context<Self>,
 7754    ) {
 7755        if self.show_edit_predictions_in_menu() {
 7756            self.update_edit_prediction_preview(&modifiers, window, cx);
 7757        }
 7758
 7759        self.update_selection_mode(&modifiers, position_map, window, cx);
 7760
 7761        let mouse_position = window.mouse_position();
 7762        if !position_map.text_hitbox.is_hovered(window) {
 7763            return;
 7764        }
 7765
 7766        self.update_hovered_link(
 7767            position_map.point_for_position(mouse_position),
 7768            &position_map.snapshot,
 7769            modifiers,
 7770            window,
 7771            cx,
 7772        )
 7773    }
 7774
 7775    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7776        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7777        if invert {
 7778            match multi_cursor_setting {
 7779                MultiCursorModifier::Alt => modifiers.alt,
 7780                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7781            }
 7782        } else {
 7783            match multi_cursor_setting {
 7784                MultiCursorModifier::Alt => modifiers.secondary(),
 7785                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7786            }
 7787        }
 7788    }
 7789
 7790    fn columnar_selection_mode(
 7791        modifiers: &Modifiers,
 7792        cx: &mut Context<Self>,
 7793    ) -> Option<ColumnarMode> {
 7794        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7795            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7796                Some(ColumnarMode::FromMouse)
 7797            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7798                Some(ColumnarMode::FromSelection)
 7799            } else {
 7800                None
 7801            }
 7802        } else {
 7803            None
 7804        }
 7805    }
 7806
 7807    fn update_selection_mode(
 7808        &mut self,
 7809        modifiers: &Modifiers,
 7810        position_map: &PositionMap,
 7811        window: &mut Window,
 7812        cx: &mut Context<Self>,
 7813    ) {
 7814        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7815            return;
 7816        };
 7817        if self.selections.pending_anchor().is_none() {
 7818            return;
 7819        }
 7820
 7821        let mouse_position = window.mouse_position();
 7822        let point_for_position = position_map.point_for_position(mouse_position);
 7823        let position = point_for_position.previous_valid;
 7824
 7825        self.select(
 7826            SelectPhase::BeginColumnar {
 7827                position,
 7828                reset: false,
 7829                mode,
 7830                goal_column: point_for_position.exact_unclipped.column(),
 7831            },
 7832            window,
 7833            cx,
 7834        );
 7835    }
 7836
 7837    fn update_edit_prediction_preview(
 7838        &mut self,
 7839        modifiers: &Modifiers,
 7840        window: &mut Window,
 7841        cx: &mut Context<Self>,
 7842    ) {
 7843        let mut modifiers_held = false;
 7844        if let Some(accept_keystroke) = self
 7845            .accept_edit_prediction_keybind(false, window, cx)
 7846            .keystroke()
 7847        {
 7848            modifiers_held = modifiers_held
 7849                || (accept_keystroke.modifiers() == modifiers
 7850                    && accept_keystroke.modifiers().modified());
 7851        };
 7852        if let Some(accept_partial_keystroke) = self
 7853            .accept_edit_prediction_keybind(true, window, cx)
 7854            .keystroke()
 7855        {
 7856            modifiers_held = modifiers_held
 7857                || (accept_partial_keystroke.modifiers() == modifiers
 7858                    && accept_partial_keystroke.modifiers().modified());
 7859        }
 7860
 7861        if modifiers_held {
 7862            if matches!(
 7863                self.edit_prediction_preview,
 7864                EditPredictionPreview::Inactive { .. }
 7865            ) {
 7866                self.edit_prediction_preview = EditPredictionPreview::Active {
 7867                    previous_scroll_position: None,
 7868                    since: Instant::now(),
 7869                };
 7870
 7871                self.update_visible_edit_prediction(window, cx);
 7872                cx.notify();
 7873            }
 7874        } else if let EditPredictionPreview::Active {
 7875            previous_scroll_position,
 7876            since,
 7877        } = self.edit_prediction_preview
 7878        {
 7879            if let (Some(previous_scroll_position), Some(position_map)) =
 7880                (previous_scroll_position, self.last_position_map.as_ref())
 7881            {
 7882                self.set_scroll_position(
 7883                    previous_scroll_position
 7884                        .scroll_position(&position_map.snapshot.display_snapshot),
 7885                    window,
 7886                    cx,
 7887                );
 7888            }
 7889
 7890            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7891                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7892            };
 7893            self.clear_row_highlights::<EditPredictionPreview>();
 7894            self.update_visible_edit_prediction(window, cx);
 7895            cx.notify();
 7896        }
 7897    }
 7898
 7899    fn update_visible_edit_prediction(
 7900        &mut self,
 7901        _window: &mut Window,
 7902        cx: &mut Context<Self>,
 7903    ) -> Option<()> {
 7904        if DisableAiSettings::get_global(cx).disable_ai {
 7905            return None;
 7906        }
 7907
 7908        if self.ime_transaction.is_some() {
 7909            self.discard_edit_prediction(false, cx);
 7910            return None;
 7911        }
 7912
 7913        let selection = self.selections.newest_anchor();
 7914        let cursor = selection.head();
 7915        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7916        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7917        let excerpt_id = cursor.excerpt_id;
 7918
 7919        let show_in_menu = self.show_edit_predictions_in_menu();
 7920        let completions_menu_has_precedence = !show_in_menu
 7921            && (self.context_menu.borrow().is_some()
 7922                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7923
 7924        if completions_menu_has_precedence
 7925            || !offset_selection.is_empty()
 7926            || self
 7927                .active_edit_prediction
 7928                .as_ref()
 7929                .is_some_and(|completion| {
 7930                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7931                        return false;
 7932                    };
 7933                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7934                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7935                    !invalidation_range.contains(&offset_selection.head())
 7936                })
 7937        {
 7938            self.discard_edit_prediction(false, cx);
 7939            return None;
 7940        }
 7941
 7942        self.take_active_edit_prediction(cx);
 7943        let Some(provider) = self.edit_prediction_provider() else {
 7944            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7945            return None;
 7946        };
 7947
 7948        let (buffer, cursor_buffer_position) =
 7949            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7950
 7951        self.edit_prediction_settings =
 7952            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7953
 7954        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7955
 7956        if self.edit_prediction_indent_conflict {
 7957            let cursor_point = cursor.to_point(&multibuffer);
 7958
 7959            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7960
 7961            if let Some((_, indent)) = indents.iter().next()
 7962                && indent.len == cursor_point.column
 7963            {
 7964                self.edit_prediction_indent_conflict = false;
 7965            }
 7966        }
 7967
 7968        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7969
 7970        let (completion_id, edits, edit_preview) = match edit_prediction {
 7971            edit_prediction::EditPrediction::Local {
 7972                id,
 7973                edits,
 7974                edit_preview,
 7975            } => (id, edits, edit_preview),
 7976            edit_prediction::EditPrediction::Jump {
 7977                id,
 7978                snapshot,
 7979                target,
 7980            } => {
 7981                self.stale_edit_prediction_in_menu = None;
 7982                self.active_edit_prediction = Some(EditPredictionState {
 7983                    inlay_ids: vec![],
 7984                    completion: EditPrediction::MoveOutside { snapshot, target },
 7985                    completion_id: id,
 7986                    invalidation_range: None,
 7987                });
 7988                cx.notify();
 7989                return Some(());
 7990            }
 7991        };
 7992
 7993        let edits = edits
 7994            .into_iter()
 7995            .flat_map(|(range, new_text)| {
 7996                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7997                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7998                Some((start..end, new_text))
 7999            })
 8000            .collect::<Vec<_>>();
 8001        if edits.is_empty() {
 8002            return None;
 8003        }
 8004
 8005        let first_edit_start = edits.first().unwrap().0.start;
 8006        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8007        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8008
 8009        let last_edit_end = edits.last().unwrap().0.end;
 8010        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8011        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8012
 8013        let cursor_row = cursor.to_point(&multibuffer).row;
 8014
 8015        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8016
 8017        let mut inlay_ids = Vec::new();
 8018        let invalidation_row_range;
 8019        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8020            Some(cursor_row..edit_end_row)
 8021        } else if cursor_row > edit_end_row {
 8022            Some(edit_start_row..cursor_row)
 8023        } else {
 8024            None
 8025        };
 8026        let supports_jump = self
 8027            .edit_prediction_provider
 8028            .as_ref()
 8029            .map(|provider| provider.provider.supports_jump_to_edit())
 8030            .unwrap_or(true);
 8031
 8032        let is_move = supports_jump
 8033            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8034        let completion = if is_move {
 8035            invalidation_row_range =
 8036                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8037            let target = first_edit_start;
 8038            EditPrediction::MoveWithin { target, snapshot }
 8039        } else {
 8040            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8041                && !self.edit_predictions_hidden_for_vim_mode;
 8042
 8043            if show_completions_in_buffer {
 8044                if edits
 8045                    .iter()
 8046                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8047                {
 8048                    let mut inlays = Vec::new();
 8049                    for (range, new_text) in &edits {
 8050                        let inlay = Inlay::edit_prediction(
 8051                            post_inc(&mut self.next_inlay_id),
 8052                            range.start,
 8053                            new_text.as_str(),
 8054                        );
 8055                        inlay_ids.push(inlay.id);
 8056                        inlays.push(inlay);
 8057                    }
 8058
 8059                    self.splice_inlays(&[], inlays, cx);
 8060                } else {
 8061                    let background_color = cx.theme().status().deleted_background;
 8062                    self.highlight_text::<EditPredictionHighlight>(
 8063                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8064                        HighlightStyle {
 8065                            background_color: Some(background_color),
 8066                            ..Default::default()
 8067                        },
 8068                        cx,
 8069                    );
 8070                }
 8071            }
 8072
 8073            invalidation_row_range = edit_start_row..edit_end_row;
 8074
 8075            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8076                if provider.show_tab_accept_marker() {
 8077                    EditDisplayMode::TabAccept
 8078                } else {
 8079                    EditDisplayMode::Inline
 8080                }
 8081            } else {
 8082                EditDisplayMode::DiffPopover
 8083            };
 8084
 8085            EditPrediction::Edit {
 8086                edits,
 8087                edit_preview,
 8088                display_mode,
 8089                snapshot,
 8090            }
 8091        };
 8092
 8093        let invalidation_range = multibuffer
 8094            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8095            ..multibuffer.anchor_after(Point::new(
 8096                invalidation_row_range.end,
 8097                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8098            ));
 8099
 8100        self.stale_edit_prediction_in_menu = None;
 8101        self.active_edit_prediction = Some(EditPredictionState {
 8102            inlay_ids,
 8103            completion,
 8104            completion_id,
 8105            invalidation_range: Some(invalidation_range),
 8106        });
 8107
 8108        cx.notify();
 8109
 8110        Some(())
 8111    }
 8112
 8113    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8114        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8115    }
 8116
 8117    fn clear_tasks(&mut self) {
 8118        self.tasks.clear()
 8119    }
 8120
 8121    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8122        if self.tasks.insert(key, value).is_some() {
 8123            // This case should hopefully be rare, but just in case...
 8124            log::error!(
 8125                "multiple different run targets found on a single line, only the last target will be rendered"
 8126            )
 8127        }
 8128    }
 8129
 8130    /// Get all display points of breakpoints that will be rendered within editor
 8131    ///
 8132    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8133    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8134    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8135    fn active_breakpoints(
 8136        &self,
 8137        range: Range<DisplayRow>,
 8138        window: &mut Window,
 8139        cx: &mut Context<Self>,
 8140    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8141        let mut breakpoint_display_points = HashMap::default();
 8142
 8143        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8144            return breakpoint_display_points;
 8145        };
 8146
 8147        let snapshot = self.snapshot(window, cx);
 8148
 8149        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8150        let Some(project) = self.project() else {
 8151            return breakpoint_display_points;
 8152        };
 8153
 8154        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8155            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8156
 8157        for (buffer_snapshot, range, excerpt_id) in
 8158            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8159        {
 8160            let Some(buffer) = project
 8161                .read(cx)
 8162                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8163            else {
 8164                continue;
 8165            };
 8166            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8167                &buffer,
 8168                Some(
 8169                    buffer_snapshot.anchor_before(range.start)
 8170                        ..buffer_snapshot.anchor_after(range.end),
 8171                ),
 8172                buffer_snapshot,
 8173                cx,
 8174            );
 8175            for (breakpoint, state) in breakpoints {
 8176                let multi_buffer_anchor =
 8177                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8178                let position = multi_buffer_anchor
 8179                    .to_point(multi_buffer_snapshot)
 8180                    .to_display_point(&snapshot);
 8181
 8182                breakpoint_display_points.insert(
 8183                    position.row(),
 8184                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8185                );
 8186            }
 8187        }
 8188
 8189        breakpoint_display_points
 8190    }
 8191
 8192    fn breakpoint_context_menu(
 8193        &self,
 8194        anchor: Anchor,
 8195        window: &mut Window,
 8196        cx: &mut Context<Self>,
 8197    ) -> Entity<ui::ContextMenu> {
 8198        let weak_editor = cx.weak_entity();
 8199        let focus_handle = self.focus_handle(cx);
 8200
 8201        let row = self
 8202            .buffer
 8203            .read(cx)
 8204            .snapshot(cx)
 8205            .summary_for_anchor::<Point>(&anchor)
 8206            .row;
 8207
 8208        let breakpoint = self
 8209            .breakpoint_at_row(row, window, cx)
 8210            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8211
 8212        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8213            "Edit Log Breakpoint"
 8214        } else {
 8215            "Set Log Breakpoint"
 8216        };
 8217
 8218        let condition_breakpoint_msg = if breakpoint
 8219            .as_ref()
 8220            .is_some_and(|bp| bp.1.condition.is_some())
 8221        {
 8222            "Edit Condition Breakpoint"
 8223        } else {
 8224            "Set Condition Breakpoint"
 8225        };
 8226
 8227        let hit_condition_breakpoint_msg = if breakpoint
 8228            .as_ref()
 8229            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8230        {
 8231            "Edit Hit Condition Breakpoint"
 8232        } else {
 8233            "Set Hit Condition Breakpoint"
 8234        };
 8235
 8236        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8237            "Unset Breakpoint"
 8238        } else {
 8239            "Set Breakpoint"
 8240        };
 8241
 8242        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8243
 8244        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8245            BreakpointState::Enabled => Some("Disable"),
 8246            BreakpointState::Disabled => Some("Enable"),
 8247        });
 8248
 8249        let (anchor, breakpoint) =
 8250            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8251
 8252        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8253            menu.on_blur_subscription(Subscription::new(|| {}))
 8254                .context(focus_handle)
 8255                .when(run_to_cursor, |this| {
 8256                    let weak_editor = weak_editor.clone();
 8257                    this.entry("Run to cursor", None, move |window, cx| {
 8258                        weak_editor
 8259                            .update(cx, |editor, cx| {
 8260                                editor.change_selections(
 8261                                    SelectionEffects::no_scroll(),
 8262                                    window,
 8263                                    cx,
 8264                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8265                                );
 8266                            })
 8267                            .ok();
 8268
 8269                        window.dispatch_action(Box::new(RunToCursor), cx);
 8270                    })
 8271                    .separator()
 8272                })
 8273                .when_some(toggle_state_msg, |this, msg| {
 8274                    this.entry(msg, None, {
 8275                        let weak_editor = weak_editor.clone();
 8276                        let breakpoint = breakpoint.clone();
 8277                        move |_window, cx| {
 8278                            weak_editor
 8279                                .update(cx, |this, cx| {
 8280                                    this.edit_breakpoint_at_anchor(
 8281                                        anchor,
 8282                                        breakpoint.as_ref().clone(),
 8283                                        BreakpointEditAction::InvertState,
 8284                                        cx,
 8285                                    );
 8286                                })
 8287                                .log_err();
 8288                        }
 8289                    })
 8290                })
 8291                .entry(set_breakpoint_msg, None, {
 8292                    let weak_editor = weak_editor.clone();
 8293                    let breakpoint = breakpoint.clone();
 8294                    move |_window, cx| {
 8295                        weak_editor
 8296                            .update(cx, |this, cx| {
 8297                                this.edit_breakpoint_at_anchor(
 8298                                    anchor,
 8299                                    breakpoint.as_ref().clone(),
 8300                                    BreakpointEditAction::Toggle,
 8301                                    cx,
 8302                                );
 8303                            })
 8304                            .log_err();
 8305                    }
 8306                })
 8307                .entry(log_breakpoint_msg, None, {
 8308                    let breakpoint = breakpoint.clone();
 8309                    let weak_editor = weak_editor.clone();
 8310                    move |window, cx| {
 8311                        weak_editor
 8312                            .update(cx, |this, cx| {
 8313                                this.add_edit_breakpoint_block(
 8314                                    anchor,
 8315                                    breakpoint.as_ref(),
 8316                                    BreakpointPromptEditAction::Log,
 8317                                    window,
 8318                                    cx,
 8319                                );
 8320                            })
 8321                            .log_err();
 8322                    }
 8323                })
 8324                .entry(condition_breakpoint_msg, None, {
 8325                    let breakpoint = breakpoint.clone();
 8326                    let weak_editor = weak_editor.clone();
 8327                    move |window, cx| {
 8328                        weak_editor
 8329                            .update(cx, |this, cx| {
 8330                                this.add_edit_breakpoint_block(
 8331                                    anchor,
 8332                                    breakpoint.as_ref(),
 8333                                    BreakpointPromptEditAction::Condition,
 8334                                    window,
 8335                                    cx,
 8336                                );
 8337                            })
 8338                            .log_err();
 8339                    }
 8340                })
 8341                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8342                    weak_editor
 8343                        .update(cx, |this, cx| {
 8344                            this.add_edit_breakpoint_block(
 8345                                anchor,
 8346                                breakpoint.as_ref(),
 8347                                BreakpointPromptEditAction::HitCondition,
 8348                                window,
 8349                                cx,
 8350                            );
 8351                        })
 8352                        .log_err();
 8353                })
 8354        })
 8355    }
 8356
 8357    fn render_breakpoint(
 8358        &self,
 8359        position: Anchor,
 8360        row: DisplayRow,
 8361        breakpoint: &Breakpoint,
 8362        state: Option<BreakpointSessionState>,
 8363        cx: &mut Context<Self>,
 8364    ) -> IconButton {
 8365        let is_rejected = state.is_some_and(|s| !s.verified);
 8366        // Is it a breakpoint that shows up when hovering over gutter?
 8367        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8368            (false, false),
 8369            |PhantomBreakpointIndicator {
 8370                 is_active,
 8371                 display_row,
 8372                 collides_with_existing_breakpoint,
 8373             }| {
 8374                (
 8375                    is_active && display_row == row,
 8376                    collides_with_existing_breakpoint,
 8377                )
 8378            },
 8379        );
 8380
 8381        let (color, icon) = {
 8382            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8383                (false, false) => ui::IconName::DebugBreakpoint,
 8384                (true, false) => ui::IconName::DebugLogBreakpoint,
 8385                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8386                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8387            };
 8388
 8389            let color = if is_phantom {
 8390                Color::Hint
 8391            } else if is_rejected {
 8392                Color::Disabled
 8393            } else {
 8394                Color::Debugger
 8395            };
 8396
 8397            (color, icon)
 8398        };
 8399
 8400        let breakpoint = Arc::from(breakpoint.clone());
 8401
 8402        let alt_as_text = gpui::Keystroke {
 8403            modifiers: Modifiers::secondary_key(),
 8404            ..Default::default()
 8405        };
 8406        let primary_action_text = if breakpoint.is_disabled() {
 8407            "Enable breakpoint"
 8408        } else if is_phantom && !collides_with_existing {
 8409            "Set breakpoint"
 8410        } else {
 8411            "Unset breakpoint"
 8412        };
 8413        let focus_handle = self.focus_handle.clone();
 8414
 8415        let meta = if is_rejected {
 8416            SharedString::from("No executable code is associated with this line.")
 8417        } else if collides_with_existing && !breakpoint.is_disabled() {
 8418            SharedString::from(format!(
 8419                "{alt_as_text}-click to disable,\nright-click for more options."
 8420            ))
 8421        } else {
 8422            SharedString::from("Right-click for more options.")
 8423        };
 8424        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8425            .icon_size(IconSize::XSmall)
 8426            .size(ui::ButtonSize::None)
 8427            .when(is_rejected, |this| {
 8428                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8429            })
 8430            .icon_color(color)
 8431            .style(ButtonStyle::Transparent)
 8432            .on_click(cx.listener({
 8433                move |editor, event: &ClickEvent, window, cx| {
 8434                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8435                        BreakpointEditAction::InvertState
 8436                    } else {
 8437                        BreakpointEditAction::Toggle
 8438                    };
 8439
 8440                    window.focus(&editor.focus_handle(cx));
 8441                    editor.edit_breakpoint_at_anchor(
 8442                        position,
 8443                        breakpoint.as_ref().clone(),
 8444                        edit_action,
 8445                        cx,
 8446                    );
 8447                }
 8448            }))
 8449            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8450                editor.set_breakpoint_context_menu(
 8451                    row,
 8452                    Some(position),
 8453                    event.position(),
 8454                    window,
 8455                    cx,
 8456                );
 8457            }))
 8458            .tooltip(move |window, cx| {
 8459                Tooltip::with_meta_in(
 8460                    primary_action_text,
 8461                    Some(&ToggleBreakpoint),
 8462                    meta.clone(),
 8463                    &focus_handle,
 8464                    window,
 8465                    cx,
 8466                )
 8467            })
 8468    }
 8469
 8470    fn build_tasks_context(
 8471        project: &Entity<Project>,
 8472        buffer: &Entity<Buffer>,
 8473        buffer_row: u32,
 8474        tasks: &Arc<RunnableTasks>,
 8475        cx: &mut Context<Self>,
 8476    ) -> Task<Option<task::TaskContext>> {
 8477        let position = Point::new(buffer_row, tasks.column);
 8478        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8479        let location = Location {
 8480            buffer: buffer.clone(),
 8481            range: range_start..range_start,
 8482        };
 8483        // Fill in the environmental variables from the tree-sitter captures
 8484        let mut captured_task_variables = TaskVariables::default();
 8485        for (capture_name, value) in tasks.extra_variables.clone() {
 8486            captured_task_variables.insert(
 8487                task::VariableName::Custom(capture_name.into()),
 8488                value.clone(),
 8489            );
 8490        }
 8491        project.update(cx, |project, cx| {
 8492            project.task_store().update(cx, |task_store, cx| {
 8493                task_store.task_context_for_location(captured_task_variables, location, cx)
 8494            })
 8495        })
 8496    }
 8497
 8498    pub fn spawn_nearest_task(
 8499        &mut self,
 8500        action: &SpawnNearestTask,
 8501        window: &mut Window,
 8502        cx: &mut Context<Self>,
 8503    ) {
 8504        let Some((workspace, _)) = self.workspace.clone() else {
 8505            return;
 8506        };
 8507        let Some(project) = self.project.clone() else {
 8508            return;
 8509        };
 8510
 8511        // Try to find a closest, enclosing node using tree-sitter that has a task
 8512        let Some((buffer, buffer_row, tasks)) = self
 8513            .find_enclosing_node_task(cx)
 8514            // Or find the task that's closest in row-distance.
 8515            .or_else(|| self.find_closest_task(cx))
 8516        else {
 8517            return;
 8518        };
 8519
 8520        let reveal_strategy = action.reveal;
 8521        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8522        cx.spawn_in(window, async move |_, cx| {
 8523            let context = task_context.await?;
 8524            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8525
 8526            let resolved = &mut resolved_task.resolved;
 8527            resolved.reveal = reveal_strategy;
 8528
 8529            workspace
 8530                .update_in(cx, |workspace, window, cx| {
 8531                    workspace.schedule_resolved_task(
 8532                        task_source_kind,
 8533                        resolved_task,
 8534                        false,
 8535                        window,
 8536                        cx,
 8537                    );
 8538                })
 8539                .ok()
 8540        })
 8541        .detach();
 8542    }
 8543
 8544    fn find_closest_task(
 8545        &mut self,
 8546        cx: &mut Context<Self>,
 8547    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8548        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8549
 8550        let ((buffer_id, row), tasks) = self
 8551            .tasks
 8552            .iter()
 8553            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8554
 8555        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8556        let tasks = Arc::new(tasks.to_owned());
 8557        Some((buffer, *row, tasks))
 8558    }
 8559
 8560    fn find_enclosing_node_task(
 8561        &mut self,
 8562        cx: &mut Context<Self>,
 8563    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8564        let snapshot = self.buffer.read(cx).snapshot(cx);
 8565        let offset = self.selections.newest::<usize>(cx).head();
 8566        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8567        let buffer_id = excerpt.buffer().remote_id();
 8568
 8569        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8570        let mut cursor = layer.node().walk();
 8571
 8572        while cursor.goto_first_child_for_byte(offset).is_some() {
 8573            if cursor.node().end_byte() == offset {
 8574                cursor.goto_next_sibling();
 8575            }
 8576        }
 8577
 8578        // Ascend to the smallest ancestor that contains the range and has a task.
 8579        loop {
 8580            let node = cursor.node();
 8581            let node_range = node.byte_range();
 8582            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8583
 8584            // Check if this node contains our offset
 8585            if node_range.start <= offset && node_range.end >= offset {
 8586                // If it contains offset, check for task
 8587                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8588                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8589                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8590                }
 8591            }
 8592
 8593            if !cursor.goto_parent() {
 8594                break;
 8595            }
 8596        }
 8597        None
 8598    }
 8599
 8600    fn render_run_indicator(
 8601        &self,
 8602        _style: &EditorStyle,
 8603        is_active: bool,
 8604        row: DisplayRow,
 8605        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8606        cx: &mut Context<Self>,
 8607    ) -> IconButton {
 8608        let color = Color::Muted;
 8609        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8610
 8611        IconButton::new(
 8612            ("run_indicator", row.0 as usize),
 8613            ui::IconName::PlayOutlined,
 8614        )
 8615        .shape(ui::IconButtonShape::Square)
 8616        .icon_size(IconSize::XSmall)
 8617        .icon_color(color)
 8618        .toggle_state(is_active)
 8619        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8620            let quick_launch = match e {
 8621                ClickEvent::Keyboard(_) => true,
 8622                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8623            };
 8624
 8625            window.focus(&editor.focus_handle(cx));
 8626            editor.toggle_code_actions(
 8627                &ToggleCodeActions {
 8628                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8629                    quick_launch,
 8630                },
 8631                window,
 8632                cx,
 8633            );
 8634        }))
 8635        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8636            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8637        }))
 8638    }
 8639
 8640    pub fn context_menu_visible(&self) -> bool {
 8641        !self.edit_prediction_preview_is_active()
 8642            && self
 8643                .context_menu
 8644                .borrow()
 8645                .as_ref()
 8646                .is_some_and(|menu| menu.visible())
 8647    }
 8648
 8649    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8650        self.context_menu
 8651            .borrow()
 8652            .as_ref()
 8653            .map(|menu| menu.origin())
 8654    }
 8655
 8656    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8657        self.context_menu_options = Some(options);
 8658    }
 8659
 8660    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8661    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8662
 8663    fn render_edit_prediction_popover(
 8664        &mut self,
 8665        text_bounds: &Bounds<Pixels>,
 8666        content_origin: gpui::Point<Pixels>,
 8667        right_margin: Pixels,
 8668        editor_snapshot: &EditorSnapshot,
 8669        visible_row_range: Range<DisplayRow>,
 8670        scroll_top: ScrollOffset,
 8671        scroll_bottom: ScrollOffset,
 8672        line_layouts: &[LineWithInvisibles],
 8673        line_height: Pixels,
 8674        scroll_position: gpui::Point<ScrollOffset>,
 8675        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8676        newest_selection_head: Option<DisplayPoint>,
 8677        editor_width: Pixels,
 8678        style: &EditorStyle,
 8679        window: &mut Window,
 8680        cx: &mut App,
 8681    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8682        if self.mode().is_minimap() {
 8683            return None;
 8684        }
 8685        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8686
 8687        if self.edit_prediction_visible_in_cursor_popover(true) {
 8688            return None;
 8689        }
 8690
 8691        match &active_edit_prediction.completion {
 8692            EditPrediction::MoveWithin { target, .. } => {
 8693                let target_display_point = target.to_display_point(editor_snapshot);
 8694
 8695                if self.edit_prediction_requires_modifier() {
 8696                    if !self.edit_prediction_preview_is_active() {
 8697                        return None;
 8698                    }
 8699
 8700                    self.render_edit_prediction_modifier_jump_popover(
 8701                        text_bounds,
 8702                        content_origin,
 8703                        visible_row_range,
 8704                        line_layouts,
 8705                        line_height,
 8706                        scroll_pixel_position,
 8707                        newest_selection_head,
 8708                        target_display_point,
 8709                        window,
 8710                        cx,
 8711                    )
 8712                } else {
 8713                    self.render_edit_prediction_eager_jump_popover(
 8714                        text_bounds,
 8715                        content_origin,
 8716                        editor_snapshot,
 8717                        visible_row_range,
 8718                        scroll_top,
 8719                        scroll_bottom,
 8720                        line_height,
 8721                        scroll_pixel_position,
 8722                        target_display_point,
 8723                        editor_width,
 8724                        window,
 8725                        cx,
 8726                    )
 8727                }
 8728            }
 8729            EditPrediction::Edit {
 8730                display_mode: EditDisplayMode::Inline,
 8731                ..
 8732            } => None,
 8733            EditPrediction::Edit {
 8734                display_mode: EditDisplayMode::TabAccept,
 8735                edits,
 8736                ..
 8737            } => {
 8738                let range = &edits.first()?.0;
 8739                let target_display_point = range.end.to_display_point(editor_snapshot);
 8740
 8741                self.render_edit_prediction_end_of_line_popover(
 8742                    "Accept",
 8743                    editor_snapshot,
 8744                    visible_row_range,
 8745                    target_display_point,
 8746                    line_height,
 8747                    scroll_pixel_position,
 8748                    content_origin,
 8749                    editor_width,
 8750                    window,
 8751                    cx,
 8752                )
 8753            }
 8754            EditPrediction::Edit {
 8755                edits,
 8756                edit_preview,
 8757                display_mode: EditDisplayMode::DiffPopover,
 8758                snapshot,
 8759            } => self.render_edit_prediction_diff_popover(
 8760                text_bounds,
 8761                content_origin,
 8762                right_margin,
 8763                editor_snapshot,
 8764                visible_row_range,
 8765                line_layouts,
 8766                line_height,
 8767                scroll_position,
 8768                scroll_pixel_position,
 8769                newest_selection_head,
 8770                editor_width,
 8771                style,
 8772                edits,
 8773                edit_preview,
 8774                snapshot,
 8775                window,
 8776                cx,
 8777            ),
 8778            EditPrediction::MoveOutside { snapshot, .. } => {
 8779                let file_name = snapshot
 8780                    .file()
 8781                    .map(|file| file.file_name(cx))
 8782                    .unwrap_or("untitled");
 8783                let mut element = self
 8784                    .render_edit_prediction_line_popover(
 8785                        format!("Jump to {file_name}"),
 8786                        Some(IconName::ZedPredict),
 8787                        window,
 8788                        cx,
 8789                    )
 8790                    .into_any();
 8791
 8792                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8793                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8794                let origin_y = text_bounds.size.height - size.height - px(30.);
 8795                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8796                element.prepaint_at(origin, window, cx);
 8797
 8798                Some((element, origin))
 8799            }
 8800        }
 8801    }
 8802
 8803    fn render_edit_prediction_modifier_jump_popover(
 8804        &mut self,
 8805        text_bounds: &Bounds<Pixels>,
 8806        content_origin: gpui::Point<Pixels>,
 8807        visible_row_range: Range<DisplayRow>,
 8808        line_layouts: &[LineWithInvisibles],
 8809        line_height: Pixels,
 8810        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8811        newest_selection_head: Option<DisplayPoint>,
 8812        target_display_point: DisplayPoint,
 8813        window: &mut Window,
 8814        cx: &mut App,
 8815    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8816        let scrolled_content_origin =
 8817            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8818
 8819        const SCROLL_PADDING_Y: Pixels = px(12.);
 8820
 8821        if target_display_point.row() < visible_row_range.start {
 8822            return self.render_edit_prediction_scroll_popover(
 8823                |_| SCROLL_PADDING_Y,
 8824                IconName::ArrowUp,
 8825                visible_row_range,
 8826                line_layouts,
 8827                newest_selection_head,
 8828                scrolled_content_origin,
 8829                window,
 8830                cx,
 8831            );
 8832        } else if target_display_point.row() >= visible_row_range.end {
 8833            return self.render_edit_prediction_scroll_popover(
 8834                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8835                IconName::ArrowDown,
 8836                visible_row_range,
 8837                line_layouts,
 8838                newest_selection_head,
 8839                scrolled_content_origin,
 8840                window,
 8841                cx,
 8842            );
 8843        }
 8844
 8845        const POLE_WIDTH: Pixels = px(2.);
 8846
 8847        let line_layout =
 8848            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8849        let target_column = target_display_point.column() as usize;
 8850
 8851        let target_x = line_layout.x_for_index(target_column);
 8852        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8853            - scroll_pixel_position.y;
 8854
 8855        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8856
 8857        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8858        border_color.l += 0.001;
 8859
 8860        let mut element = v_flex()
 8861            .items_end()
 8862            .when(flag_on_right, |el| el.items_start())
 8863            .child(if flag_on_right {
 8864                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8865                    .rounded_bl(px(0.))
 8866                    .rounded_tl(px(0.))
 8867                    .border_l_2()
 8868                    .border_color(border_color)
 8869            } else {
 8870                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8871                    .rounded_br(px(0.))
 8872                    .rounded_tr(px(0.))
 8873                    .border_r_2()
 8874                    .border_color(border_color)
 8875            })
 8876            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8877            .into_any();
 8878
 8879        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8880
 8881        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8882            - point(
 8883                if flag_on_right {
 8884                    POLE_WIDTH
 8885                } else {
 8886                    size.width - POLE_WIDTH
 8887                },
 8888                size.height - line_height,
 8889            );
 8890
 8891        origin.x = origin.x.max(content_origin.x);
 8892
 8893        element.prepaint_at(origin, window, cx);
 8894
 8895        Some((element, origin))
 8896    }
 8897
 8898    fn render_edit_prediction_scroll_popover(
 8899        &mut self,
 8900        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8901        scroll_icon: IconName,
 8902        visible_row_range: Range<DisplayRow>,
 8903        line_layouts: &[LineWithInvisibles],
 8904        newest_selection_head: Option<DisplayPoint>,
 8905        scrolled_content_origin: gpui::Point<Pixels>,
 8906        window: &mut Window,
 8907        cx: &mut App,
 8908    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8909        let mut element = self
 8910            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8911            .into_any();
 8912
 8913        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8914
 8915        let cursor = newest_selection_head?;
 8916        let cursor_row_layout =
 8917            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8918        let cursor_column = cursor.column() as usize;
 8919
 8920        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8921
 8922        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8923
 8924        element.prepaint_at(origin, window, cx);
 8925        Some((element, origin))
 8926    }
 8927
 8928    fn render_edit_prediction_eager_jump_popover(
 8929        &mut self,
 8930        text_bounds: &Bounds<Pixels>,
 8931        content_origin: gpui::Point<Pixels>,
 8932        editor_snapshot: &EditorSnapshot,
 8933        visible_row_range: Range<DisplayRow>,
 8934        scroll_top: ScrollOffset,
 8935        scroll_bottom: ScrollOffset,
 8936        line_height: Pixels,
 8937        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8938        target_display_point: DisplayPoint,
 8939        editor_width: Pixels,
 8940        window: &mut Window,
 8941        cx: &mut App,
 8942    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8943        if target_display_point.row().as_f64() < scroll_top {
 8944            let mut element = self
 8945                .render_edit_prediction_line_popover(
 8946                    "Jump to Edit",
 8947                    Some(IconName::ArrowUp),
 8948                    window,
 8949                    cx,
 8950                )
 8951                .into_any();
 8952
 8953            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8954            let offset = point(
 8955                (text_bounds.size.width - size.width) / 2.,
 8956                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8957            );
 8958
 8959            let origin = text_bounds.origin + offset;
 8960            element.prepaint_at(origin, window, cx);
 8961            Some((element, origin))
 8962        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8963            let mut element = self
 8964                .render_edit_prediction_line_popover(
 8965                    "Jump to Edit",
 8966                    Some(IconName::ArrowDown),
 8967                    window,
 8968                    cx,
 8969                )
 8970                .into_any();
 8971
 8972            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8973            let offset = point(
 8974                (text_bounds.size.width - size.width) / 2.,
 8975                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8976            );
 8977
 8978            let origin = text_bounds.origin + offset;
 8979            element.prepaint_at(origin, window, cx);
 8980            Some((element, origin))
 8981        } else {
 8982            self.render_edit_prediction_end_of_line_popover(
 8983                "Jump to Edit",
 8984                editor_snapshot,
 8985                visible_row_range,
 8986                target_display_point,
 8987                line_height,
 8988                scroll_pixel_position,
 8989                content_origin,
 8990                editor_width,
 8991                window,
 8992                cx,
 8993            )
 8994        }
 8995    }
 8996
 8997    fn render_edit_prediction_end_of_line_popover(
 8998        self: &mut Editor,
 8999        label: &'static str,
 9000        editor_snapshot: &EditorSnapshot,
 9001        visible_row_range: Range<DisplayRow>,
 9002        target_display_point: DisplayPoint,
 9003        line_height: Pixels,
 9004        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9005        content_origin: gpui::Point<Pixels>,
 9006        editor_width: Pixels,
 9007        window: &mut Window,
 9008        cx: &mut App,
 9009    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9010        let target_line_end = DisplayPoint::new(
 9011            target_display_point.row(),
 9012            editor_snapshot.line_len(target_display_point.row()),
 9013        );
 9014
 9015        let mut element = self
 9016            .render_edit_prediction_line_popover(label, None, window, cx)
 9017            .into_any();
 9018
 9019        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9020
 9021        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9022
 9023        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9024        let mut origin = start_point
 9025            + line_origin
 9026            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9027        origin.x = origin.x.max(content_origin.x);
 9028
 9029        let max_x = content_origin.x + editor_width - size.width;
 9030
 9031        if origin.x > max_x {
 9032            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9033
 9034            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9035                origin.y += offset;
 9036                IconName::ArrowUp
 9037            } else {
 9038                origin.y -= offset;
 9039                IconName::ArrowDown
 9040            };
 9041
 9042            element = self
 9043                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9044                .into_any();
 9045
 9046            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9047
 9048            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9049        }
 9050
 9051        element.prepaint_at(origin, window, cx);
 9052        Some((element, origin))
 9053    }
 9054
 9055    fn render_edit_prediction_diff_popover(
 9056        self: &Editor,
 9057        text_bounds: &Bounds<Pixels>,
 9058        content_origin: gpui::Point<Pixels>,
 9059        right_margin: Pixels,
 9060        editor_snapshot: &EditorSnapshot,
 9061        visible_row_range: Range<DisplayRow>,
 9062        line_layouts: &[LineWithInvisibles],
 9063        line_height: Pixels,
 9064        scroll_position: gpui::Point<ScrollOffset>,
 9065        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9066        newest_selection_head: Option<DisplayPoint>,
 9067        editor_width: Pixels,
 9068        style: &EditorStyle,
 9069        edits: &Vec<(Range<Anchor>, String)>,
 9070        edit_preview: &Option<language::EditPreview>,
 9071        snapshot: &language::BufferSnapshot,
 9072        window: &mut Window,
 9073        cx: &mut App,
 9074    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9075        let edit_start = edits
 9076            .first()
 9077            .unwrap()
 9078            .0
 9079            .start
 9080            .to_display_point(editor_snapshot);
 9081        let edit_end = edits
 9082            .last()
 9083            .unwrap()
 9084            .0
 9085            .end
 9086            .to_display_point(editor_snapshot);
 9087
 9088        let is_visible = visible_row_range.contains(&edit_start.row())
 9089            || visible_row_range.contains(&edit_end.row());
 9090        if !is_visible {
 9091            return None;
 9092        }
 9093
 9094        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9095            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9096        } else {
 9097            // Fallback for providers without edit_preview
 9098            crate::edit_prediction_fallback_text(edits, cx)
 9099        };
 9100
 9101        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9102        let line_count = highlighted_edits.text.lines().count();
 9103
 9104        const BORDER_WIDTH: Pixels = px(1.);
 9105
 9106        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9107        let has_keybind = keybind.is_some();
 9108
 9109        let mut element = h_flex()
 9110            .items_start()
 9111            .child(
 9112                h_flex()
 9113                    .bg(cx.theme().colors().editor_background)
 9114                    .border(BORDER_WIDTH)
 9115                    .shadow_xs()
 9116                    .border_color(cx.theme().colors().border)
 9117                    .rounded_l_lg()
 9118                    .when(line_count > 1, |el| el.rounded_br_lg())
 9119                    .pr_1()
 9120                    .child(styled_text),
 9121            )
 9122            .child(
 9123                h_flex()
 9124                    .h(line_height + BORDER_WIDTH * 2.)
 9125                    .px_1p5()
 9126                    .gap_1()
 9127                    // Workaround: For some reason, there's a gap if we don't do this
 9128                    .ml(-BORDER_WIDTH)
 9129                    .shadow(vec![gpui::BoxShadow {
 9130                        color: gpui::black().opacity(0.05),
 9131                        offset: point(px(1.), px(1.)),
 9132                        blur_radius: px(2.),
 9133                        spread_radius: px(0.),
 9134                    }])
 9135                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9136                    .border(BORDER_WIDTH)
 9137                    .border_color(cx.theme().colors().border)
 9138                    .rounded_r_lg()
 9139                    .id("edit_prediction_diff_popover_keybind")
 9140                    .when(!has_keybind, |el| {
 9141                        let status_colors = cx.theme().status();
 9142
 9143                        el.bg(status_colors.error_background)
 9144                            .border_color(status_colors.error.opacity(0.6))
 9145                            .child(Icon::new(IconName::Info).color(Color::Error))
 9146                            .cursor_default()
 9147                            .hoverable_tooltip(move |_window, cx| {
 9148                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9149                            })
 9150                    })
 9151                    .children(keybind),
 9152            )
 9153            .into_any();
 9154
 9155        let longest_row =
 9156            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9157        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9158            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9159        } else {
 9160            layout_line(
 9161                longest_row,
 9162                editor_snapshot,
 9163                style,
 9164                editor_width,
 9165                |_| false,
 9166                window,
 9167                cx,
 9168            )
 9169            .width
 9170        };
 9171
 9172        let viewport_bounds =
 9173            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9174                right: -right_margin,
 9175                ..Default::default()
 9176            });
 9177
 9178        let x_after_longest = Pixels::from(
 9179            ScrollPixelOffset::from(
 9180                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9181            ) - scroll_pixel_position.x,
 9182        );
 9183
 9184        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9185
 9186        // Fully visible if it can be displayed within the window (allow overlapping other
 9187        // panes). However, this is only allowed if the popover starts within text_bounds.
 9188        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9189            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9190
 9191        let mut origin = if can_position_to_the_right {
 9192            point(
 9193                x_after_longest,
 9194                text_bounds.origin.y
 9195                    + Pixels::from(
 9196                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9197                            - scroll_pixel_position.y,
 9198                    ),
 9199            )
 9200        } else {
 9201            let cursor_row = newest_selection_head.map(|head| head.row());
 9202            let above_edit = edit_start
 9203                .row()
 9204                .0
 9205                .checked_sub(line_count as u32)
 9206                .map(DisplayRow);
 9207            let below_edit = Some(edit_end.row() + 1);
 9208            let above_cursor =
 9209                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9210            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9211
 9212            // Place the edit popover adjacent to the edit if there is a location
 9213            // available that is onscreen and does not obscure the cursor. Otherwise,
 9214            // place it adjacent to the cursor.
 9215            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9216                .into_iter()
 9217                .flatten()
 9218                .find(|&start_row| {
 9219                    let end_row = start_row + line_count as u32;
 9220                    visible_row_range.contains(&start_row)
 9221                        && visible_row_range.contains(&end_row)
 9222                        && cursor_row
 9223                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9224                })?;
 9225
 9226            content_origin
 9227                + point(
 9228                    Pixels::from(-scroll_pixel_position.x),
 9229                    Pixels::from(
 9230                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9231                    ),
 9232                )
 9233        };
 9234
 9235        origin.x -= BORDER_WIDTH;
 9236
 9237        window.defer_draw(element, origin, 1);
 9238
 9239        // Do not return an element, since it will already be drawn due to defer_draw.
 9240        None
 9241    }
 9242
 9243    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9244        px(30.)
 9245    }
 9246
 9247    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9248        if self.read_only(cx) {
 9249            cx.theme().players().read_only()
 9250        } else {
 9251            self.style.as_ref().unwrap().local_player
 9252        }
 9253    }
 9254
 9255    fn render_edit_prediction_accept_keybind(
 9256        &self,
 9257        window: &mut Window,
 9258        cx: &App,
 9259    ) -> Option<AnyElement> {
 9260        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9261        let accept_keystroke = accept_binding.keystroke()?;
 9262
 9263        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9264
 9265        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9266            Color::Accent
 9267        } else {
 9268            Color::Muted
 9269        };
 9270
 9271        h_flex()
 9272            .px_0p5()
 9273            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9274            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9275            .text_size(TextSize::XSmall.rems(cx))
 9276            .child(h_flex().children(ui::render_modifiers(
 9277                accept_keystroke.modifiers(),
 9278                PlatformStyle::platform(),
 9279                Some(modifiers_color),
 9280                Some(IconSize::XSmall.rems().into()),
 9281                true,
 9282            )))
 9283            .when(is_platform_style_mac, |parent| {
 9284                parent.child(accept_keystroke.key().to_string())
 9285            })
 9286            .when(!is_platform_style_mac, |parent| {
 9287                parent.child(
 9288                    Key::new(
 9289                        util::capitalize(accept_keystroke.key()),
 9290                        Some(Color::Default),
 9291                    )
 9292                    .size(Some(IconSize::XSmall.rems().into())),
 9293                )
 9294            })
 9295            .into_any()
 9296            .into()
 9297    }
 9298
 9299    fn render_edit_prediction_line_popover(
 9300        &self,
 9301        label: impl Into<SharedString>,
 9302        icon: Option<IconName>,
 9303        window: &mut Window,
 9304        cx: &App,
 9305    ) -> Stateful<Div> {
 9306        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9307
 9308        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9309        let has_keybind = keybind.is_some();
 9310
 9311        h_flex()
 9312            .id("ep-line-popover")
 9313            .py_0p5()
 9314            .pl_1()
 9315            .pr(padding_right)
 9316            .gap_1()
 9317            .rounded_md()
 9318            .border_1()
 9319            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9320            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9321            .shadow_xs()
 9322            .when(!has_keybind, |el| {
 9323                let status_colors = cx.theme().status();
 9324
 9325                el.bg(status_colors.error_background)
 9326                    .border_color(status_colors.error.opacity(0.6))
 9327                    .pl_2()
 9328                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9329                    .cursor_default()
 9330                    .hoverable_tooltip(move |_window, cx| {
 9331                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9332                    })
 9333            })
 9334            .children(keybind)
 9335            .child(
 9336                Label::new(label)
 9337                    .size(LabelSize::Small)
 9338                    .when(!has_keybind, |el| {
 9339                        el.color(cx.theme().status().error.into()).strikethrough()
 9340                    }),
 9341            )
 9342            .when(!has_keybind, |el| {
 9343                el.child(
 9344                    h_flex().ml_1().child(
 9345                        Icon::new(IconName::Info)
 9346                            .size(IconSize::Small)
 9347                            .color(cx.theme().status().error.into()),
 9348                    ),
 9349                )
 9350            })
 9351            .when_some(icon, |element, icon| {
 9352                element.child(
 9353                    div()
 9354                        .mt(px(1.5))
 9355                        .child(Icon::new(icon).size(IconSize::Small)),
 9356                )
 9357            })
 9358    }
 9359
 9360    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9361        let accent_color = cx.theme().colors().text_accent;
 9362        let editor_bg_color = cx.theme().colors().editor_background;
 9363        editor_bg_color.blend(accent_color.opacity(0.1))
 9364    }
 9365
 9366    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9367        let accent_color = cx.theme().colors().text_accent;
 9368        let editor_bg_color = cx.theme().colors().editor_background;
 9369        editor_bg_color.blend(accent_color.opacity(0.6))
 9370    }
 9371    fn get_prediction_provider_icon_name(
 9372        provider: &Option<RegisteredEditPredictionProvider>,
 9373    ) -> IconName {
 9374        match provider {
 9375            Some(provider) => match provider.provider.name() {
 9376                "copilot" => IconName::Copilot,
 9377                "supermaven" => IconName::Supermaven,
 9378                _ => IconName::ZedPredict,
 9379            },
 9380            None => IconName::ZedPredict,
 9381        }
 9382    }
 9383
 9384    fn render_edit_prediction_cursor_popover(
 9385        &self,
 9386        min_width: Pixels,
 9387        max_width: Pixels,
 9388        cursor_point: Point,
 9389        style: &EditorStyle,
 9390        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9391        _window: &Window,
 9392        cx: &mut Context<Editor>,
 9393    ) -> Option<AnyElement> {
 9394        let provider = self.edit_prediction_provider.as_ref()?;
 9395        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9396
 9397        let is_refreshing = provider.provider.is_refreshing(cx);
 9398
 9399        fn pending_completion_container(icon: IconName) -> Div {
 9400            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9401        }
 9402
 9403        let completion = match &self.active_edit_prediction {
 9404            Some(prediction) => {
 9405                if !self.has_visible_completions_menu() {
 9406                    const RADIUS: Pixels = px(6.);
 9407                    const BORDER_WIDTH: Pixels = px(1.);
 9408
 9409                    return Some(
 9410                        h_flex()
 9411                            .elevation_2(cx)
 9412                            .border(BORDER_WIDTH)
 9413                            .border_color(cx.theme().colors().border)
 9414                            .when(accept_keystroke.is_none(), |el| {
 9415                                el.border_color(cx.theme().status().error)
 9416                            })
 9417                            .rounded(RADIUS)
 9418                            .rounded_tl(px(0.))
 9419                            .overflow_hidden()
 9420                            .child(div().px_1p5().child(match &prediction.completion {
 9421                                EditPrediction::MoveWithin { target, snapshot } => {
 9422                                    use text::ToPoint as _;
 9423                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9424                                    {
 9425                                        Icon::new(IconName::ZedPredictDown)
 9426                                    } else {
 9427                                        Icon::new(IconName::ZedPredictUp)
 9428                                    }
 9429                                }
 9430                                EditPrediction::MoveOutside { .. } => {
 9431                                    // TODO [zeta2] custom icon for external jump?
 9432                                    Icon::new(provider_icon)
 9433                                }
 9434                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9435                            }))
 9436                            .child(
 9437                                h_flex()
 9438                                    .gap_1()
 9439                                    .py_1()
 9440                                    .px_2()
 9441                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9442                                    .border_l_1()
 9443                                    .border_color(cx.theme().colors().border)
 9444                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9445                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9446                                        el.child(
 9447                                            Label::new("Hold")
 9448                                                .size(LabelSize::Small)
 9449                                                .when(accept_keystroke.is_none(), |el| {
 9450                                                    el.strikethrough()
 9451                                                })
 9452                                                .line_height_style(LineHeightStyle::UiLabel),
 9453                                        )
 9454                                    })
 9455                                    .id("edit_prediction_cursor_popover_keybind")
 9456                                    .when(accept_keystroke.is_none(), |el| {
 9457                                        let status_colors = cx.theme().status();
 9458
 9459                                        el.bg(status_colors.error_background)
 9460                                            .border_color(status_colors.error.opacity(0.6))
 9461                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9462                                            .cursor_default()
 9463                                            .hoverable_tooltip(move |_window, cx| {
 9464                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9465                                                    .into()
 9466                                            })
 9467                                    })
 9468                                    .when_some(
 9469                                        accept_keystroke.as_ref(),
 9470                                        |el, accept_keystroke| {
 9471                                            el.child(h_flex().children(ui::render_modifiers(
 9472                                                accept_keystroke.modifiers(),
 9473                                                PlatformStyle::platform(),
 9474                                                Some(Color::Default),
 9475                                                Some(IconSize::XSmall.rems().into()),
 9476                                                false,
 9477                                            )))
 9478                                        },
 9479                                    ),
 9480                            )
 9481                            .into_any(),
 9482                    );
 9483                }
 9484
 9485                self.render_edit_prediction_cursor_popover_preview(
 9486                    prediction,
 9487                    cursor_point,
 9488                    style,
 9489                    cx,
 9490                )?
 9491            }
 9492
 9493            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9494                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9495                    stale_completion,
 9496                    cursor_point,
 9497                    style,
 9498                    cx,
 9499                )?,
 9500
 9501                None => pending_completion_container(provider_icon)
 9502                    .child(Label::new("...").size(LabelSize::Small)),
 9503            },
 9504
 9505            None => pending_completion_container(provider_icon)
 9506                .child(Label::new("...").size(LabelSize::Small)),
 9507        };
 9508
 9509        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9510            completion
 9511                .with_animation(
 9512                    "loading-completion",
 9513                    Animation::new(Duration::from_secs(2))
 9514                        .repeat()
 9515                        .with_easing(pulsating_between(0.4, 0.8)),
 9516                    |label, delta| label.opacity(delta),
 9517                )
 9518                .into_any_element()
 9519        } else {
 9520            completion.into_any_element()
 9521        };
 9522
 9523        let has_completion = self.active_edit_prediction.is_some();
 9524
 9525        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9526        Some(
 9527            h_flex()
 9528                .min_w(min_width)
 9529                .max_w(max_width)
 9530                .flex_1()
 9531                .elevation_2(cx)
 9532                .border_color(cx.theme().colors().border)
 9533                .child(
 9534                    div()
 9535                        .flex_1()
 9536                        .py_1()
 9537                        .px_2()
 9538                        .overflow_hidden()
 9539                        .child(completion),
 9540                )
 9541                .when_some(accept_keystroke, |el, accept_keystroke| {
 9542                    if !accept_keystroke.modifiers().modified() {
 9543                        return el;
 9544                    }
 9545
 9546                    el.child(
 9547                        h_flex()
 9548                            .h_full()
 9549                            .border_l_1()
 9550                            .rounded_r_lg()
 9551                            .border_color(cx.theme().colors().border)
 9552                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9553                            .gap_1()
 9554                            .py_1()
 9555                            .px_2()
 9556                            .child(
 9557                                h_flex()
 9558                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9559                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9560                                    .child(h_flex().children(ui::render_modifiers(
 9561                                        accept_keystroke.modifiers(),
 9562                                        PlatformStyle::platform(),
 9563                                        Some(if !has_completion {
 9564                                            Color::Muted
 9565                                        } else {
 9566                                            Color::Default
 9567                                        }),
 9568                                        None,
 9569                                        false,
 9570                                    ))),
 9571                            )
 9572                            .child(Label::new("Preview").into_any_element())
 9573                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9574                    )
 9575                })
 9576                .into_any(),
 9577        )
 9578    }
 9579
 9580    fn render_edit_prediction_cursor_popover_preview(
 9581        &self,
 9582        completion: &EditPredictionState,
 9583        cursor_point: Point,
 9584        style: &EditorStyle,
 9585        cx: &mut Context<Editor>,
 9586    ) -> Option<Div> {
 9587        use text::ToPoint as _;
 9588
 9589        fn render_relative_row_jump(
 9590            prefix: impl Into<String>,
 9591            current_row: u32,
 9592            target_row: u32,
 9593        ) -> Div {
 9594            let (row_diff, arrow) = if target_row < current_row {
 9595                (current_row - target_row, IconName::ArrowUp)
 9596            } else {
 9597                (target_row - current_row, IconName::ArrowDown)
 9598            };
 9599
 9600            h_flex()
 9601                .child(
 9602                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9603                        .color(Color::Muted)
 9604                        .size(LabelSize::Small),
 9605                )
 9606                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9607        }
 9608
 9609        let supports_jump = self
 9610            .edit_prediction_provider
 9611            .as_ref()
 9612            .map(|provider| provider.provider.supports_jump_to_edit())
 9613            .unwrap_or(true);
 9614
 9615        match &completion.completion {
 9616            EditPrediction::MoveWithin {
 9617                target, snapshot, ..
 9618            } => {
 9619                if !supports_jump {
 9620                    return None;
 9621                }
 9622
 9623                Some(
 9624                    h_flex()
 9625                        .px_2()
 9626                        .gap_2()
 9627                        .flex_1()
 9628                        .child(
 9629                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9630                                Icon::new(IconName::ZedPredictDown)
 9631                            } else {
 9632                                Icon::new(IconName::ZedPredictUp)
 9633                            },
 9634                        )
 9635                        .child(Label::new("Jump to Edit")),
 9636                )
 9637            }
 9638            EditPrediction::MoveOutside { snapshot, .. } => {
 9639                let file_name = snapshot
 9640                    .file()
 9641                    .map(|file| file.file_name(cx))
 9642                    .unwrap_or("untitled");
 9643                Some(
 9644                    h_flex()
 9645                        .px_2()
 9646                        .gap_2()
 9647                        .flex_1()
 9648                        .child(Icon::new(IconName::ZedPredict))
 9649                        .child(Label::new(format!("Jump to {file_name}"))),
 9650                )
 9651            }
 9652            EditPrediction::Edit {
 9653                edits,
 9654                edit_preview,
 9655                snapshot,
 9656                display_mode: _,
 9657            } => {
 9658                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9659
 9660                let (highlighted_edits, has_more_lines) =
 9661                    if let Some(edit_preview) = edit_preview.as_ref() {
 9662                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9663                            .first_line_preview()
 9664                    } else {
 9665                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9666                    };
 9667
 9668                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9669                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9670
 9671                let preview = h_flex()
 9672                    .gap_1()
 9673                    .min_w_16()
 9674                    .child(styled_text)
 9675                    .when(has_more_lines, |parent| parent.child(""));
 9676
 9677                let left = if supports_jump && first_edit_row != cursor_point.row {
 9678                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9679                        .into_any_element()
 9680                } else {
 9681                    let icon_name =
 9682                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9683                    Icon::new(icon_name).into_any_element()
 9684                };
 9685
 9686                Some(
 9687                    h_flex()
 9688                        .h_full()
 9689                        .flex_1()
 9690                        .gap_2()
 9691                        .pr_1()
 9692                        .overflow_x_hidden()
 9693                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9694                        .child(left)
 9695                        .child(preview),
 9696                )
 9697            }
 9698        }
 9699    }
 9700
 9701    pub fn render_context_menu(
 9702        &self,
 9703        style: &EditorStyle,
 9704        max_height_in_lines: u32,
 9705        window: &mut Window,
 9706        cx: &mut Context<Editor>,
 9707    ) -> Option<AnyElement> {
 9708        let menu = self.context_menu.borrow();
 9709        let menu = menu.as_ref()?;
 9710        if !menu.visible() {
 9711            return None;
 9712        };
 9713        Some(menu.render(style, max_height_in_lines, window, cx))
 9714    }
 9715
 9716    fn render_context_menu_aside(
 9717        &mut self,
 9718        max_size: Size<Pixels>,
 9719        window: &mut Window,
 9720        cx: &mut Context<Editor>,
 9721    ) -> Option<AnyElement> {
 9722        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9723            if menu.visible() {
 9724                menu.render_aside(max_size, window, cx)
 9725            } else {
 9726                None
 9727            }
 9728        })
 9729    }
 9730
 9731    fn hide_context_menu(
 9732        &mut self,
 9733        window: &mut Window,
 9734        cx: &mut Context<Self>,
 9735    ) -> Option<CodeContextMenu> {
 9736        cx.notify();
 9737        self.completion_tasks.clear();
 9738        let context_menu = self.context_menu.borrow_mut().take();
 9739        self.stale_edit_prediction_in_menu.take();
 9740        self.update_visible_edit_prediction(window, cx);
 9741        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9742            && let Some(completion_provider) = &self.completion_provider
 9743        {
 9744            completion_provider.selection_changed(None, window, cx);
 9745        }
 9746        context_menu
 9747    }
 9748
 9749    fn show_snippet_choices(
 9750        &mut self,
 9751        choices: &Vec<String>,
 9752        selection: Range<Anchor>,
 9753        cx: &mut Context<Self>,
 9754    ) {
 9755        let Some((_, buffer, _)) = self
 9756            .buffer()
 9757            .read(cx)
 9758            .excerpt_containing(selection.start, cx)
 9759        else {
 9760            return;
 9761        };
 9762        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9763        else {
 9764            return;
 9765        };
 9766        if buffer != end_buffer {
 9767            log::error!("expected anchor range to have matching buffer IDs");
 9768            return;
 9769        }
 9770
 9771        let id = post_inc(&mut self.next_completion_id);
 9772        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9773        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9774            CompletionsMenu::new_snippet_choices(
 9775                id,
 9776                true,
 9777                choices,
 9778                selection,
 9779                buffer,
 9780                snippet_sort_order,
 9781            ),
 9782        ));
 9783    }
 9784
 9785    pub fn insert_snippet(
 9786        &mut self,
 9787        insertion_ranges: &[Range<usize>],
 9788        snippet: Snippet,
 9789        window: &mut Window,
 9790        cx: &mut Context<Self>,
 9791    ) -> Result<()> {
 9792        struct Tabstop<T> {
 9793            is_end_tabstop: bool,
 9794            ranges: Vec<Range<T>>,
 9795            choices: Option<Vec<String>>,
 9796        }
 9797
 9798        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9799            let snippet_text: Arc<str> = snippet.text.clone().into();
 9800            let edits = insertion_ranges
 9801                .iter()
 9802                .cloned()
 9803                .map(|range| (range, snippet_text.clone()));
 9804            let autoindent_mode = AutoindentMode::Block {
 9805                original_indent_columns: Vec::new(),
 9806            };
 9807            buffer.edit(edits, Some(autoindent_mode), cx);
 9808
 9809            let snapshot = &*buffer.read(cx);
 9810            let snippet = &snippet;
 9811            snippet
 9812                .tabstops
 9813                .iter()
 9814                .map(|tabstop| {
 9815                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9816                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9817                    });
 9818                    let mut tabstop_ranges = tabstop
 9819                        .ranges
 9820                        .iter()
 9821                        .flat_map(|tabstop_range| {
 9822                            let mut delta = 0_isize;
 9823                            insertion_ranges.iter().map(move |insertion_range| {
 9824                                let insertion_start = insertion_range.start as isize + delta;
 9825                                delta +=
 9826                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9827
 9828                                let start = ((insertion_start + tabstop_range.start) as usize)
 9829                                    .min(snapshot.len());
 9830                                let end = ((insertion_start + tabstop_range.end) as usize)
 9831                                    .min(snapshot.len());
 9832                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9833                            })
 9834                        })
 9835                        .collect::<Vec<_>>();
 9836                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9837
 9838                    Tabstop {
 9839                        is_end_tabstop,
 9840                        ranges: tabstop_ranges,
 9841                        choices: tabstop.choices.clone(),
 9842                    }
 9843                })
 9844                .collect::<Vec<_>>()
 9845        });
 9846        if let Some(tabstop) = tabstops.first() {
 9847            self.change_selections(Default::default(), window, cx, |s| {
 9848                // Reverse order so that the first range is the newest created selection.
 9849                // Completions will use it and autoscroll will prioritize it.
 9850                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9851            });
 9852
 9853            if let Some(choices) = &tabstop.choices
 9854                && let Some(selection) = tabstop.ranges.first()
 9855            {
 9856                self.show_snippet_choices(choices, selection.clone(), cx)
 9857            }
 9858
 9859            // If we're already at the last tabstop and it's at the end of the snippet,
 9860            // we're done, we don't need to keep the state around.
 9861            if !tabstop.is_end_tabstop {
 9862                let choices = tabstops
 9863                    .iter()
 9864                    .map(|tabstop| tabstop.choices.clone())
 9865                    .collect();
 9866
 9867                let ranges = tabstops
 9868                    .into_iter()
 9869                    .map(|tabstop| tabstop.ranges)
 9870                    .collect::<Vec<_>>();
 9871
 9872                self.snippet_stack.push(SnippetState {
 9873                    active_index: 0,
 9874                    ranges,
 9875                    choices,
 9876                });
 9877            }
 9878
 9879            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9880            if self.autoclose_regions.is_empty() {
 9881                let snapshot = self.buffer.read(cx).snapshot(cx);
 9882                let mut all_selections = self.selections.all::<Point>(cx);
 9883                for selection in &mut all_selections {
 9884                    let selection_head = selection.head();
 9885                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9886                        continue;
 9887                    };
 9888
 9889                    let mut bracket_pair = None;
 9890                    let max_lookup_length = scope
 9891                        .brackets()
 9892                        .map(|(pair, _)| {
 9893                            pair.start
 9894                                .as_str()
 9895                                .chars()
 9896                                .count()
 9897                                .max(pair.end.as_str().chars().count())
 9898                        })
 9899                        .max();
 9900                    if let Some(max_lookup_length) = max_lookup_length {
 9901                        let next_text = snapshot
 9902                            .chars_at(selection_head)
 9903                            .take(max_lookup_length)
 9904                            .collect::<String>();
 9905                        let prev_text = snapshot
 9906                            .reversed_chars_at(selection_head)
 9907                            .take(max_lookup_length)
 9908                            .collect::<String>();
 9909
 9910                        for (pair, enabled) in scope.brackets() {
 9911                            if enabled
 9912                                && pair.close
 9913                                && prev_text.starts_with(pair.start.as_str())
 9914                                && next_text.starts_with(pair.end.as_str())
 9915                            {
 9916                                bracket_pair = Some(pair.clone());
 9917                                break;
 9918                            }
 9919                        }
 9920                    }
 9921
 9922                    if let Some(pair) = bracket_pair {
 9923                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9924                        let autoclose_enabled =
 9925                            self.use_autoclose && snapshot_settings.use_autoclose;
 9926                        if autoclose_enabled {
 9927                            let start = snapshot.anchor_after(selection_head);
 9928                            let end = snapshot.anchor_after(selection_head);
 9929                            self.autoclose_regions.push(AutocloseRegion {
 9930                                selection_id: selection.id,
 9931                                range: start..end,
 9932                                pair,
 9933                            });
 9934                        }
 9935                    }
 9936                }
 9937            }
 9938        }
 9939        Ok(())
 9940    }
 9941
 9942    pub fn move_to_next_snippet_tabstop(
 9943        &mut self,
 9944        window: &mut Window,
 9945        cx: &mut Context<Self>,
 9946    ) -> bool {
 9947        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9948    }
 9949
 9950    pub fn move_to_prev_snippet_tabstop(
 9951        &mut self,
 9952        window: &mut Window,
 9953        cx: &mut Context<Self>,
 9954    ) -> bool {
 9955        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9956    }
 9957
 9958    pub fn move_to_snippet_tabstop(
 9959        &mut self,
 9960        bias: Bias,
 9961        window: &mut Window,
 9962        cx: &mut Context<Self>,
 9963    ) -> bool {
 9964        if let Some(mut snippet) = self.snippet_stack.pop() {
 9965            match bias {
 9966                Bias::Left => {
 9967                    if snippet.active_index > 0 {
 9968                        snippet.active_index -= 1;
 9969                    } else {
 9970                        self.snippet_stack.push(snippet);
 9971                        return false;
 9972                    }
 9973                }
 9974                Bias::Right => {
 9975                    if snippet.active_index + 1 < snippet.ranges.len() {
 9976                        snippet.active_index += 1;
 9977                    } else {
 9978                        self.snippet_stack.push(snippet);
 9979                        return false;
 9980                    }
 9981                }
 9982            }
 9983            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9984                self.change_selections(Default::default(), window, cx, |s| {
 9985                    // Reverse order so that the first range is the newest created selection.
 9986                    // Completions will use it and autoscroll will prioritize it.
 9987                    s.select_ranges(current_ranges.iter().rev().cloned())
 9988                });
 9989
 9990                if let Some(choices) = &snippet.choices[snippet.active_index]
 9991                    && let Some(selection) = current_ranges.first()
 9992                {
 9993                    self.show_snippet_choices(choices, selection.clone(), cx);
 9994                }
 9995
 9996                // If snippet state is not at the last tabstop, push it back on the stack
 9997                if snippet.active_index + 1 < snippet.ranges.len() {
 9998                    self.snippet_stack.push(snippet);
 9999                }
10000                return true;
10001            }
10002        }
10003
10004        false
10005    }
10006
10007    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10008        self.transact(window, cx, |this, window, cx| {
10009            this.select_all(&SelectAll, window, cx);
10010            this.insert("", window, cx);
10011        });
10012    }
10013
10014    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10015        if self.read_only(cx) {
10016            return;
10017        }
10018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10019        self.transact(window, cx, |this, window, cx| {
10020            this.select_autoclose_pair(window, cx);
10021            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10022            if !this.linked_edit_ranges.is_empty() {
10023                let selections = this.selections.all::<MultiBufferPoint>(cx);
10024                let snapshot = this.buffer.read(cx).snapshot(cx);
10025
10026                for selection in selections.iter() {
10027                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10028                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10029                    if selection_start.buffer_id != selection_end.buffer_id {
10030                        continue;
10031                    }
10032                    if let Some(ranges) =
10033                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10034                    {
10035                        for (buffer, entries) in ranges {
10036                            linked_ranges.entry(buffer).or_default().extend(entries);
10037                        }
10038                    }
10039                }
10040            }
10041
10042            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10043            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10044            for selection in &mut selections {
10045                if selection.is_empty() {
10046                    let old_head = selection.head();
10047                    let mut new_head =
10048                        movement::left(&display_map, old_head.to_display_point(&display_map))
10049                            .to_point(&display_map);
10050                    if let Some((buffer, line_buffer_range)) = display_map
10051                        .buffer_snapshot()
10052                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10053                    {
10054                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10055                        let indent_len = match indent_size.kind {
10056                            IndentKind::Space => {
10057                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10058                            }
10059                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10060                        };
10061                        if old_head.column <= indent_size.len && old_head.column > 0 {
10062                            let indent_len = indent_len.get();
10063                            new_head = cmp::min(
10064                                new_head,
10065                                MultiBufferPoint::new(
10066                                    old_head.row,
10067                                    ((old_head.column - 1) / indent_len) * indent_len,
10068                                ),
10069                            );
10070                        }
10071                    }
10072
10073                    selection.set_head(new_head, SelectionGoal::None);
10074                }
10075            }
10076
10077            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10078            this.insert("", window, cx);
10079            let empty_str: Arc<str> = Arc::from("");
10080            for (buffer, edits) in linked_ranges {
10081                let snapshot = buffer.read(cx).snapshot();
10082                use text::ToPoint as TP;
10083
10084                let edits = edits
10085                    .into_iter()
10086                    .map(|range| {
10087                        let end_point = TP::to_point(&range.end, &snapshot);
10088                        let mut start_point = TP::to_point(&range.start, &snapshot);
10089
10090                        if end_point == start_point {
10091                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10092                                .saturating_sub(1);
10093                            start_point =
10094                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10095                        };
10096
10097                        (start_point..end_point, empty_str.clone())
10098                    })
10099                    .sorted_by_key(|(range, _)| range.start)
10100                    .collect::<Vec<_>>();
10101                buffer.update(cx, |this, cx| {
10102                    this.edit(edits, None, cx);
10103                })
10104            }
10105            this.refresh_edit_prediction(true, false, window, cx);
10106            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10107        });
10108    }
10109
10110    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10111        if self.read_only(cx) {
10112            return;
10113        }
10114        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10115        self.transact(window, cx, |this, window, cx| {
10116            this.change_selections(Default::default(), window, cx, |s| {
10117                s.move_with(|map, selection| {
10118                    if selection.is_empty() {
10119                        let cursor = movement::right(map, selection.head());
10120                        selection.end = cursor;
10121                        selection.reversed = true;
10122                        selection.goal = SelectionGoal::None;
10123                    }
10124                })
10125            });
10126            this.insert("", window, cx);
10127            this.refresh_edit_prediction(true, false, window, cx);
10128        });
10129    }
10130
10131    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10132        if self.mode.is_single_line() {
10133            cx.propagate();
10134            return;
10135        }
10136
10137        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10138        if self.move_to_prev_snippet_tabstop(window, cx) {
10139            return;
10140        }
10141        self.outdent(&Outdent, window, cx);
10142    }
10143
10144    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10145        if self.mode.is_single_line() {
10146            cx.propagate();
10147            return;
10148        }
10149
10150        if self.move_to_next_snippet_tabstop(window, cx) {
10151            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10152            return;
10153        }
10154        if self.read_only(cx) {
10155            return;
10156        }
10157        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10158        let mut selections = self.selections.all_adjusted(cx);
10159        let buffer = self.buffer.read(cx);
10160        let snapshot = buffer.snapshot(cx);
10161        let rows_iter = selections.iter().map(|s| s.head().row);
10162        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10163
10164        let has_some_cursor_in_whitespace = selections
10165            .iter()
10166            .filter(|selection| selection.is_empty())
10167            .any(|selection| {
10168                let cursor = selection.head();
10169                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10170                cursor.column < current_indent.len
10171            });
10172
10173        let mut edits = Vec::new();
10174        let mut prev_edited_row = 0;
10175        let mut row_delta = 0;
10176        for selection in &mut selections {
10177            if selection.start.row != prev_edited_row {
10178                row_delta = 0;
10179            }
10180            prev_edited_row = selection.end.row;
10181
10182            // If the selection is non-empty, then increase the indentation of the selected lines.
10183            if !selection.is_empty() {
10184                row_delta =
10185                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10186                continue;
10187            }
10188
10189            let cursor = selection.head();
10190            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10191            if let Some(suggested_indent) =
10192                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10193            {
10194                // Don't do anything if already at suggested indent
10195                // and there is any other cursor which is not
10196                if has_some_cursor_in_whitespace
10197                    && cursor.column == current_indent.len
10198                    && current_indent.len == suggested_indent.len
10199                {
10200                    continue;
10201                }
10202
10203                // Adjust line and move cursor to suggested indent
10204                // if cursor is not at suggested indent
10205                if cursor.column < suggested_indent.len
10206                    && cursor.column <= current_indent.len
10207                    && current_indent.len <= suggested_indent.len
10208                {
10209                    selection.start = Point::new(cursor.row, suggested_indent.len);
10210                    selection.end = selection.start;
10211                    if row_delta == 0 {
10212                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10213                            cursor.row,
10214                            current_indent,
10215                            suggested_indent,
10216                        ));
10217                        row_delta = suggested_indent.len - current_indent.len;
10218                    }
10219                    continue;
10220                }
10221
10222                // If current indent is more than suggested indent
10223                // only move cursor to current indent and skip indent
10224                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10225                    selection.start = Point::new(cursor.row, current_indent.len);
10226                    selection.end = selection.start;
10227                    continue;
10228                }
10229            }
10230
10231            // Otherwise, insert a hard or soft tab.
10232            let settings = buffer.language_settings_at(cursor, cx);
10233            let tab_size = if settings.hard_tabs {
10234                IndentSize::tab()
10235            } else {
10236                let tab_size = settings.tab_size.get();
10237                let indent_remainder = snapshot
10238                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10239                    .flat_map(str::chars)
10240                    .fold(row_delta % tab_size, |counter: u32, c| {
10241                        if c == '\t' {
10242                            0
10243                        } else {
10244                            (counter + 1) % tab_size
10245                        }
10246                    });
10247
10248                let chars_to_next_tab_stop = tab_size - indent_remainder;
10249                IndentSize::spaces(chars_to_next_tab_stop)
10250            };
10251            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10252            selection.end = selection.start;
10253            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10254            row_delta += tab_size.len;
10255        }
10256
10257        self.transact(window, cx, |this, window, cx| {
10258            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10259            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10260            this.refresh_edit_prediction(true, false, window, cx);
10261        });
10262    }
10263
10264    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10265        if self.read_only(cx) {
10266            return;
10267        }
10268        if self.mode.is_single_line() {
10269            cx.propagate();
10270            return;
10271        }
10272
10273        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10274        let mut selections = self.selections.all::<Point>(cx);
10275        let mut prev_edited_row = 0;
10276        let mut row_delta = 0;
10277        let mut edits = Vec::new();
10278        let buffer = self.buffer.read(cx);
10279        let snapshot = buffer.snapshot(cx);
10280        for selection in &mut selections {
10281            if selection.start.row != prev_edited_row {
10282                row_delta = 0;
10283            }
10284            prev_edited_row = selection.end.row;
10285
10286            row_delta =
10287                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10288        }
10289
10290        self.transact(window, cx, |this, window, cx| {
10291            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10292            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10293        });
10294    }
10295
10296    fn indent_selection(
10297        buffer: &MultiBuffer,
10298        snapshot: &MultiBufferSnapshot,
10299        selection: &mut Selection<Point>,
10300        edits: &mut Vec<(Range<Point>, String)>,
10301        delta_for_start_row: u32,
10302        cx: &App,
10303    ) -> u32 {
10304        let settings = buffer.language_settings_at(selection.start, cx);
10305        let tab_size = settings.tab_size.get();
10306        let indent_kind = if settings.hard_tabs {
10307            IndentKind::Tab
10308        } else {
10309            IndentKind::Space
10310        };
10311        let mut start_row = selection.start.row;
10312        let mut end_row = selection.end.row + 1;
10313
10314        // If a selection ends at the beginning of a line, don't indent
10315        // that last line.
10316        if selection.end.column == 0 && selection.end.row > selection.start.row {
10317            end_row -= 1;
10318        }
10319
10320        // Avoid re-indenting a row that has already been indented by a
10321        // previous selection, but still update this selection's column
10322        // to reflect that indentation.
10323        if delta_for_start_row > 0 {
10324            start_row += 1;
10325            selection.start.column += delta_for_start_row;
10326            if selection.end.row == selection.start.row {
10327                selection.end.column += delta_for_start_row;
10328            }
10329        }
10330
10331        let mut delta_for_end_row = 0;
10332        let has_multiple_rows = start_row + 1 != end_row;
10333        for row in start_row..end_row {
10334            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10335            let indent_delta = match (current_indent.kind, indent_kind) {
10336                (IndentKind::Space, IndentKind::Space) => {
10337                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10338                    IndentSize::spaces(columns_to_next_tab_stop)
10339                }
10340                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10341                (_, IndentKind::Tab) => IndentSize::tab(),
10342            };
10343
10344            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10345                0
10346            } else {
10347                selection.start.column
10348            };
10349            let row_start = Point::new(row, start);
10350            edits.push((
10351                row_start..row_start,
10352                indent_delta.chars().collect::<String>(),
10353            ));
10354
10355            // Update this selection's endpoints to reflect the indentation.
10356            if row == selection.start.row {
10357                selection.start.column += indent_delta.len;
10358            }
10359            if row == selection.end.row {
10360                selection.end.column += indent_delta.len;
10361                delta_for_end_row = indent_delta.len;
10362            }
10363        }
10364
10365        if selection.start.row == selection.end.row {
10366            delta_for_start_row + delta_for_end_row
10367        } else {
10368            delta_for_end_row
10369        }
10370    }
10371
10372    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10373        if self.read_only(cx) {
10374            return;
10375        }
10376        if self.mode.is_single_line() {
10377            cx.propagate();
10378            return;
10379        }
10380
10381        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10382        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10383        let selections = self.selections.all::<Point>(cx);
10384        let mut deletion_ranges = Vec::new();
10385        let mut last_outdent = None;
10386        {
10387            let buffer = self.buffer.read(cx);
10388            let snapshot = buffer.snapshot(cx);
10389            for selection in &selections {
10390                let settings = buffer.language_settings_at(selection.start, cx);
10391                let tab_size = settings.tab_size.get();
10392                let mut rows = selection.spanned_rows(false, &display_map);
10393
10394                // Avoid re-outdenting a row that has already been outdented by a
10395                // previous selection.
10396                if let Some(last_row) = last_outdent
10397                    && last_row == rows.start
10398                {
10399                    rows.start = rows.start.next_row();
10400                }
10401                let has_multiple_rows = rows.len() > 1;
10402                for row in rows.iter_rows() {
10403                    let indent_size = snapshot.indent_size_for_line(row);
10404                    if indent_size.len > 0 {
10405                        let deletion_len = match indent_size.kind {
10406                            IndentKind::Space => {
10407                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10408                                if columns_to_prev_tab_stop == 0 {
10409                                    tab_size
10410                                } else {
10411                                    columns_to_prev_tab_stop
10412                                }
10413                            }
10414                            IndentKind::Tab => 1,
10415                        };
10416                        let start = if has_multiple_rows
10417                            || deletion_len > selection.start.column
10418                            || indent_size.len < selection.start.column
10419                        {
10420                            0
10421                        } else {
10422                            selection.start.column - deletion_len
10423                        };
10424                        deletion_ranges.push(
10425                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10426                        );
10427                        last_outdent = Some(row);
10428                    }
10429                }
10430            }
10431        }
10432
10433        self.transact(window, cx, |this, window, cx| {
10434            this.buffer.update(cx, |buffer, cx| {
10435                let empty_str: Arc<str> = Arc::default();
10436                buffer.edit(
10437                    deletion_ranges
10438                        .into_iter()
10439                        .map(|range| (range, empty_str.clone())),
10440                    None,
10441                    cx,
10442                );
10443            });
10444            let selections = this.selections.all::<usize>(cx);
10445            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10446        });
10447    }
10448
10449    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10450        if self.read_only(cx) {
10451            return;
10452        }
10453        if self.mode.is_single_line() {
10454            cx.propagate();
10455            return;
10456        }
10457
10458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10459        let selections = self
10460            .selections
10461            .all::<usize>(cx)
10462            .into_iter()
10463            .map(|s| s.range());
10464
10465        self.transact(window, cx, |this, window, cx| {
10466            this.buffer.update(cx, |buffer, cx| {
10467                buffer.autoindent_ranges(selections, cx);
10468            });
10469            let selections = this.selections.all::<usize>(cx);
10470            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10471        });
10472    }
10473
10474    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10475        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10477        let selections = self.selections.all::<Point>(cx);
10478
10479        let mut new_cursors = Vec::new();
10480        let mut edit_ranges = Vec::new();
10481        let mut selections = selections.iter().peekable();
10482        while let Some(selection) = selections.next() {
10483            let mut rows = selection.spanned_rows(false, &display_map);
10484
10485            // Accumulate contiguous regions of rows that we want to delete.
10486            while let Some(next_selection) = selections.peek() {
10487                let next_rows = next_selection.spanned_rows(false, &display_map);
10488                if next_rows.start <= rows.end {
10489                    rows.end = next_rows.end;
10490                    selections.next().unwrap();
10491                } else {
10492                    break;
10493                }
10494            }
10495
10496            let buffer = display_map.buffer_snapshot();
10497            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10498            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10499                // If there's a line after the range, delete the \n from the end of the row range
10500                (
10501                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10502                    rows.end,
10503                )
10504            } else {
10505                // If there isn't a line after the range, delete the \n from the line before the
10506                // start of the row range
10507                edit_start = edit_start.saturating_sub(1);
10508                (buffer.len(), rows.start.previous_row())
10509            };
10510
10511            let text_layout_details = self.text_layout_details(window);
10512            let x = display_map.x_for_display_point(
10513                selection.head().to_display_point(&display_map),
10514                &text_layout_details,
10515            );
10516            let row = Point::new(target_row.0, 0)
10517                .to_display_point(&display_map)
10518                .row();
10519            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10520
10521            new_cursors.push((
10522                selection.id,
10523                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10524                SelectionGoal::None,
10525            ));
10526            edit_ranges.push(edit_start..edit_end);
10527        }
10528
10529        self.transact(window, cx, |this, window, cx| {
10530            let buffer = this.buffer.update(cx, |buffer, cx| {
10531                let empty_str: Arc<str> = Arc::default();
10532                buffer.edit(
10533                    edit_ranges
10534                        .into_iter()
10535                        .map(|range| (range, empty_str.clone())),
10536                    None,
10537                    cx,
10538                );
10539                buffer.snapshot(cx)
10540            });
10541            let new_selections = new_cursors
10542                .into_iter()
10543                .map(|(id, cursor, goal)| {
10544                    let cursor = cursor.to_point(&buffer);
10545                    Selection {
10546                        id,
10547                        start: cursor,
10548                        end: cursor,
10549                        reversed: false,
10550                        goal,
10551                    }
10552                })
10553                .collect();
10554
10555            this.change_selections(Default::default(), window, cx, |s| {
10556                s.select(new_selections);
10557            });
10558        });
10559    }
10560
10561    pub fn join_lines_impl(
10562        &mut self,
10563        insert_whitespace: bool,
10564        window: &mut Window,
10565        cx: &mut Context<Self>,
10566    ) {
10567        if self.read_only(cx) {
10568            return;
10569        }
10570        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10571        for selection in self.selections.all::<Point>(cx) {
10572            let start = MultiBufferRow(selection.start.row);
10573            // Treat single line selections as if they include the next line. Otherwise this action
10574            // would do nothing for single line selections individual cursors.
10575            let end = if selection.start.row == selection.end.row {
10576                MultiBufferRow(selection.start.row + 1)
10577            } else {
10578                MultiBufferRow(selection.end.row)
10579            };
10580
10581            if let Some(last_row_range) = row_ranges.last_mut()
10582                && start <= last_row_range.end
10583            {
10584                last_row_range.end = end;
10585                continue;
10586            }
10587            row_ranges.push(start..end);
10588        }
10589
10590        let snapshot = self.buffer.read(cx).snapshot(cx);
10591        let mut cursor_positions = Vec::new();
10592        for row_range in &row_ranges {
10593            let anchor = snapshot.anchor_before(Point::new(
10594                row_range.end.previous_row().0,
10595                snapshot.line_len(row_range.end.previous_row()),
10596            ));
10597            cursor_positions.push(anchor..anchor);
10598        }
10599
10600        self.transact(window, cx, |this, window, cx| {
10601            for row_range in row_ranges.into_iter().rev() {
10602                for row in row_range.iter_rows().rev() {
10603                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10604                    let next_line_row = row.next_row();
10605                    let indent = snapshot.indent_size_for_line(next_line_row);
10606                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10607
10608                    let replace =
10609                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10610                            " "
10611                        } else {
10612                            ""
10613                        };
10614
10615                    this.buffer.update(cx, |buffer, cx| {
10616                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10617                    });
10618                }
10619            }
10620
10621            this.change_selections(Default::default(), window, cx, |s| {
10622                s.select_anchor_ranges(cursor_positions)
10623            });
10624        });
10625    }
10626
10627    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10629        self.join_lines_impl(true, window, cx);
10630    }
10631
10632    pub fn sort_lines_case_sensitive(
10633        &mut self,
10634        _: &SortLinesCaseSensitive,
10635        window: &mut Window,
10636        cx: &mut Context<Self>,
10637    ) {
10638        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10639    }
10640
10641    pub fn sort_lines_by_length(
10642        &mut self,
10643        _: &SortLinesByLength,
10644        window: &mut Window,
10645        cx: &mut Context<Self>,
10646    ) {
10647        self.manipulate_immutable_lines(window, cx, |lines| {
10648            lines.sort_by_key(|&line| line.chars().count())
10649        })
10650    }
10651
10652    pub fn sort_lines_case_insensitive(
10653        &mut self,
10654        _: &SortLinesCaseInsensitive,
10655        window: &mut Window,
10656        cx: &mut Context<Self>,
10657    ) {
10658        self.manipulate_immutable_lines(window, cx, |lines| {
10659            lines.sort_by_key(|line| line.to_lowercase())
10660        })
10661    }
10662
10663    pub fn unique_lines_case_insensitive(
10664        &mut self,
10665        _: &UniqueLinesCaseInsensitive,
10666        window: &mut Window,
10667        cx: &mut Context<Self>,
10668    ) {
10669        self.manipulate_immutable_lines(window, cx, |lines| {
10670            let mut seen = HashSet::default();
10671            lines.retain(|line| seen.insert(line.to_lowercase()));
10672        })
10673    }
10674
10675    pub fn unique_lines_case_sensitive(
10676        &mut self,
10677        _: &UniqueLinesCaseSensitive,
10678        window: &mut Window,
10679        cx: &mut Context<Self>,
10680    ) {
10681        self.manipulate_immutable_lines(window, cx, |lines| {
10682            let mut seen = HashSet::default();
10683            lines.retain(|line| seen.insert(*line));
10684        })
10685    }
10686
10687    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10688        let snapshot = self.buffer.read(cx).snapshot(cx);
10689        for selection in self.selections.disjoint_anchors_arc().iter() {
10690            if snapshot
10691                .language_at(selection.start)
10692                .and_then(|lang| lang.config().wrap_characters.as_ref())
10693                .is_some()
10694            {
10695                return true;
10696            }
10697        }
10698        false
10699    }
10700
10701    fn wrap_selections_in_tag(
10702        &mut self,
10703        _: &WrapSelectionsInTag,
10704        window: &mut Window,
10705        cx: &mut Context<Self>,
10706    ) {
10707        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10708
10709        let snapshot = self.buffer.read(cx).snapshot(cx);
10710
10711        let mut edits = Vec::new();
10712        let mut boundaries = Vec::new();
10713
10714        for selection in self.selections.all::<Point>(cx).iter() {
10715            let Some(wrap_config) = snapshot
10716                .language_at(selection.start)
10717                .and_then(|lang| lang.config().wrap_characters.clone())
10718            else {
10719                continue;
10720            };
10721
10722            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10723            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10724
10725            let start_before = snapshot.anchor_before(selection.start);
10726            let end_after = snapshot.anchor_after(selection.end);
10727
10728            edits.push((start_before..start_before, open_tag));
10729            edits.push((end_after..end_after, close_tag));
10730
10731            boundaries.push((
10732                start_before,
10733                end_after,
10734                wrap_config.start_prefix.len(),
10735                wrap_config.end_suffix.len(),
10736            ));
10737        }
10738
10739        if edits.is_empty() {
10740            return;
10741        }
10742
10743        self.transact(window, cx, |this, window, cx| {
10744            let buffer = this.buffer.update(cx, |buffer, cx| {
10745                buffer.edit(edits, None, cx);
10746                buffer.snapshot(cx)
10747            });
10748
10749            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10750            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10751                boundaries.into_iter()
10752            {
10753                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10754                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10755                new_selections.push(open_offset..open_offset);
10756                new_selections.push(close_offset..close_offset);
10757            }
10758
10759            this.change_selections(Default::default(), window, cx, |s| {
10760                s.select_ranges(new_selections);
10761            });
10762
10763            this.request_autoscroll(Autoscroll::fit(), cx);
10764        });
10765    }
10766
10767    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10768        let Some(project) = self.project.clone() else {
10769            return;
10770        };
10771        self.reload(project, window, cx)
10772            .detach_and_notify_err(window, cx);
10773    }
10774
10775    pub fn restore_file(
10776        &mut self,
10777        _: &::git::RestoreFile,
10778        window: &mut Window,
10779        cx: &mut Context<Self>,
10780    ) {
10781        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10782        let mut buffer_ids = HashSet::default();
10783        let snapshot = self.buffer().read(cx).snapshot(cx);
10784        for selection in self.selections.all::<usize>(cx) {
10785            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10786        }
10787
10788        let buffer = self.buffer().read(cx);
10789        let ranges = buffer_ids
10790            .into_iter()
10791            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10792            .collect::<Vec<_>>();
10793
10794        self.restore_hunks_in_ranges(ranges, window, cx);
10795    }
10796
10797    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10798        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10799        let selections = self
10800            .selections
10801            .all(cx)
10802            .into_iter()
10803            .map(|s| s.range())
10804            .collect();
10805        self.restore_hunks_in_ranges(selections, window, cx);
10806    }
10807
10808    pub fn restore_hunks_in_ranges(
10809        &mut self,
10810        ranges: Vec<Range<Point>>,
10811        window: &mut Window,
10812        cx: &mut Context<Editor>,
10813    ) {
10814        let mut revert_changes = HashMap::default();
10815        let chunk_by = self
10816            .snapshot(window, cx)
10817            .hunks_for_ranges(ranges)
10818            .into_iter()
10819            .chunk_by(|hunk| hunk.buffer_id);
10820        for (buffer_id, hunks) in &chunk_by {
10821            let hunks = hunks.collect::<Vec<_>>();
10822            for hunk in &hunks {
10823                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10824            }
10825            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10826        }
10827        drop(chunk_by);
10828        if !revert_changes.is_empty() {
10829            self.transact(window, cx, |editor, window, cx| {
10830                editor.restore(revert_changes, window, cx);
10831            });
10832        }
10833    }
10834
10835    pub fn open_active_item_in_terminal(
10836        &mut self,
10837        _: &OpenInTerminal,
10838        window: &mut Window,
10839        cx: &mut Context<Self>,
10840    ) {
10841        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10842            let project_path = buffer.read(cx).project_path(cx)?;
10843            let project = self.project()?.read(cx);
10844            let entry = project.entry_for_path(&project_path, cx)?;
10845            let parent = match &entry.canonical_path {
10846                Some(canonical_path) => canonical_path.to_path_buf(),
10847                None => project.absolute_path(&project_path, cx)?,
10848            }
10849            .parent()?
10850            .to_path_buf();
10851            Some(parent)
10852        }) {
10853            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10854        }
10855    }
10856
10857    fn set_breakpoint_context_menu(
10858        &mut self,
10859        display_row: DisplayRow,
10860        position: Option<Anchor>,
10861        clicked_point: gpui::Point<Pixels>,
10862        window: &mut Window,
10863        cx: &mut Context<Self>,
10864    ) {
10865        let source = self
10866            .buffer
10867            .read(cx)
10868            .snapshot(cx)
10869            .anchor_before(Point::new(display_row.0, 0u32));
10870
10871        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10872
10873        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10874            self,
10875            source,
10876            clicked_point,
10877            context_menu,
10878            window,
10879            cx,
10880        );
10881    }
10882
10883    fn add_edit_breakpoint_block(
10884        &mut self,
10885        anchor: Anchor,
10886        breakpoint: &Breakpoint,
10887        edit_action: BreakpointPromptEditAction,
10888        window: &mut Window,
10889        cx: &mut Context<Self>,
10890    ) {
10891        let weak_editor = cx.weak_entity();
10892        let bp_prompt = cx.new(|cx| {
10893            BreakpointPromptEditor::new(
10894                weak_editor,
10895                anchor,
10896                breakpoint.clone(),
10897                edit_action,
10898                window,
10899                cx,
10900            )
10901        });
10902
10903        let height = bp_prompt.update(cx, |this, cx| {
10904            this.prompt
10905                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10906        });
10907        let cloned_prompt = bp_prompt.clone();
10908        let blocks = vec![BlockProperties {
10909            style: BlockStyle::Sticky,
10910            placement: BlockPlacement::Above(anchor),
10911            height: Some(height),
10912            render: Arc::new(move |cx| {
10913                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10914                cloned_prompt.clone().into_any_element()
10915            }),
10916            priority: 0,
10917        }];
10918
10919        let focus_handle = bp_prompt.focus_handle(cx);
10920        window.focus(&focus_handle);
10921
10922        let block_ids = self.insert_blocks(blocks, None, cx);
10923        bp_prompt.update(cx, |prompt, _| {
10924            prompt.add_block_ids(block_ids);
10925        });
10926    }
10927
10928    pub(crate) fn breakpoint_at_row(
10929        &self,
10930        row: u32,
10931        window: &mut Window,
10932        cx: &mut Context<Self>,
10933    ) -> Option<(Anchor, Breakpoint)> {
10934        let snapshot = self.snapshot(window, cx);
10935        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10936
10937        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10938    }
10939
10940    pub(crate) fn breakpoint_at_anchor(
10941        &self,
10942        breakpoint_position: Anchor,
10943        snapshot: &EditorSnapshot,
10944        cx: &mut Context<Self>,
10945    ) -> Option<(Anchor, Breakpoint)> {
10946        let buffer = self
10947            .buffer
10948            .read(cx)
10949            .buffer_for_anchor(breakpoint_position, cx)?;
10950
10951        let enclosing_excerpt = breakpoint_position.excerpt_id;
10952        let buffer_snapshot = buffer.read(cx).snapshot();
10953
10954        let row = buffer_snapshot
10955            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10956            .row;
10957
10958        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10959        let anchor_end = snapshot
10960            .buffer_snapshot()
10961            .anchor_after(Point::new(row, line_len));
10962
10963        self.breakpoint_store
10964            .as_ref()?
10965            .read_with(cx, |breakpoint_store, cx| {
10966                breakpoint_store
10967                    .breakpoints(
10968                        &buffer,
10969                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10970                        &buffer_snapshot,
10971                        cx,
10972                    )
10973                    .next()
10974                    .and_then(|(bp, _)| {
10975                        let breakpoint_row = buffer_snapshot
10976                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10977                            .row;
10978
10979                        if breakpoint_row == row {
10980                            snapshot
10981                                .buffer_snapshot()
10982                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10983                                .map(|position| (position, bp.bp.clone()))
10984                        } else {
10985                            None
10986                        }
10987                    })
10988            })
10989    }
10990
10991    pub fn edit_log_breakpoint(
10992        &mut self,
10993        _: &EditLogBreakpoint,
10994        window: &mut Window,
10995        cx: &mut Context<Self>,
10996    ) {
10997        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10998            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10999                message: None,
11000                state: BreakpointState::Enabled,
11001                condition: None,
11002                hit_condition: None,
11003            });
11004
11005            self.add_edit_breakpoint_block(
11006                anchor,
11007                &breakpoint,
11008                BreakpointPromptEditAction::Log,
11009                window,
11010                cx,
11011            );
11012        }
11013    }
11014
11015    fn breakpoints_at_cursors(
11016        &self,
11017        window: &mut Window,
11018        cx: &mut Context<Self>,
11019    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11020        let snapshot = self.snapshot(window, cx);
11021        let cursors = self
11022            .selections
11023            .disjoint_anchors_arc()
11024            .iter()
11025            .map(|selection| {
11026                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11027
11028                let breakpoint_position = self
11029                    .breakpoint_at_row(cursor_position.row, window, cx)
11030                    .map(|bp| bp.0)
11031                    .unwrap_or_else(|| {
11032                        snapshot
11033                            .display_snapshot
11034                            .buffer_snapshot()
11035                            .anchor_after(Point::new(cursor_position.row, 0))
11036                    });
11037
11038                let breakpoint = self
11039                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11040                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11041
11042                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11043            })
11044            // 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.
11045            .collect::<HashMap<Anchor, _>>();
11046
11047        cursors.into_iter().collect()
11048    }
11049
11050    pub fn enable_breakpoint(
11051        &mut self,
11052        _: &crate::actions::EnableBreakpoint,
11053        window: &mut Window,
11054        cx: &mut Context<Self>,
11055    ) {
11056        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11057            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11058                continue;
11059            };
11060            self.edit_breakpoint_at_anchor(
11061                anchor,
11062                breakpoint,
11063                BreakpointEditAction::InvertState,
11064                cx,
11065            );
11066        }
11067    }
11068
11069    pub fn disable_breakpoint(
11070        &mut self,
11071        _: &crate::actions::DisableBreakpoint,
11072        window: &mut Window,
11073        cx: &mut Context<Self>,
11074    ) {
11075        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11076            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11077                continue;
11078            };
11079            self.edit_breakpoint_at_anchor(
11080                anchor,
11081                breakpoint,
11082                BreakpointEditAction::InvertState,
11083                cx,
11084            );
11085        }
11086    }
11087
11088    pub fn toggle_breakpoint(
11089        &mut self,
11090        _: &crate::actions::ToggleBreakpoint,
11091        window: &mut Window,
11092        cx: &mut Context<Self>,
11093    ) {
11094        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11095            if let Some(breakpoint) = breakpoint {
11096                self.edit_breakpoint_at_anchor(
11097                    anchor,
11098                    breakpoint,
11099                    BreakpointEditAction::Toggle,
11100                    cx,
11101                );
11102            } else {
11103                self.edit_breakpoint_at_anchor(
11104                    anchor,
11105                    Breakpoint::new_standard(),
11106                    BreakpointEditAction::Toggle,
11107                    cx,
11108                );
11109            }
11110        }
11111    }
11112
11113    pub fn edit_breakpoint_at_anchor(
11114        &mut self,
11115        breakpoint_position: Anchor,
11116        breakpoint: Breakpoint,
11117        edit_action: BreakpointEditAction,
11118        cx: &mut Context<Self>,
11119    ) {
11120        let Some(breakpoint_store) = &self.breakpoint_store else {
11121            return;
11122        };
11123
11124        let Some(buffer) = self
11125            .buffer
11126            .read(cx)
11127            .buffer_for_anchor(breakpoint_position, cx)
11128        else {
11129            return;
11130        };
11131
11132        breakpoint_store.update(cx, |breakpoint_store, cx| {
11133            breakpoint_store.toggle_breakpoint(
11134                buffer,
11135                BreakpointWithPosition {
11136                    position: breakpoint_position.text_anchor,
11137                    bp: breakpoint,
11138                },
11139                edit_action,
11140                cx,
11141            );
11142        });
11143
11144        cx.notify();
11145    }
11146
11147    #[cfg(any(test, feature = "test-support"))]
11148    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11149        self.breakpoint_store.clone()
11150    }
11151
11152    pub fn prepare_restore_change(
11153        &self,
11154        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11155        hunk: &MultiBufferDiffHunk,
11156        cx: &mut App,
11157    ) -> Option<()> {
11158        if hunk.is_created_file() {
11159            return None;
11160        }
11161        let buffer = self.buffer.read(cx);
11162        let diff = buffer.diff_for(hunk.buffer_id)?;
11163        let buffer = buffer.buffer(hunk.buffer_id)?;
11164        let buffer = buffer.read(cx);
11165        let original_text = diff
11166            .read(cx)
11167            .base_text()
11168            .as_rope()
11169            .slice(hunk.diff_base_byte_range.clone());
11170        let buffer_snapshot = buffer.snapshot();
11171        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11172        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11173            probe
11174                .0
11175                .start
11176                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11177                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11178        }) {
11179            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11180            Some(())
11181        } else {
11182            None
11183        }
11184    }
11185
11186    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11187        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11188    }
11189
11190    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11191        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11192    }
11193
11194    fn manipulate_lines<M>(
11195        &mut self,
11196        window: &mut Window,
11197        cx: &mut Context<Self>,
11198        mut manipulate: M,
11199    ) where
11200        M: FnMut(&str) -> LineManipulationResult,
11201    {
11202        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11203
11204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11205        let buffer = self.buffer.read(cx).snapshot(cx);
11206
11207        let mut edits = Vec::new();
11208
11209        let selections = self.selections.all::<Point>(cx);
11210        let mut selections = selections.iter().peekable();
11211        let mut contiguous_row_selections = Vec::new();
11212        let mut new_selections = Vec::new();
11213        let mut added_lines = 0;
11214        let mut removed_lines = 0;
11215
11216        while let Some(selection) = selections.next() {
11217            let (start_row, end_row) = consume_contiguous_rows(
11218                &mut contiguous_row_selections,
11219                selection,
11220                &display_map,
11221                &mut selections,
11222            );
11223
11224            let start_point = Point::new(start_row.0, 0);
11225            let end_point = Point::new(
11226                end_row.previous_row().0,
11227                buffer.line_len(end_row.previous_row()),
11228            );
11229            let text = buffer
11230                .text_for_range(start_point..end_point)
11231                .collect::<String>();
11232
11233            let LineManipulationResult {
11234                new_text,
11235                line_count_before,
11236                line_count_after,
11237            } = manipulate(&text);
11238
11239            edits.push((start_point..end_point, new_text));
11240
11241            // Selections must change based on added and removed line count
11242            let start_row =
11243                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11244            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11245            new_selections.push(Selection {
11246                id: selection.id,
11247                start: start_row,
11248                end: end_row,
11249                goal: SelectionGoal::None,
11250                reversed: selection.reversed,
11251            });
11252
11253            if line_count_after > line_count_before {
11254                added_lines += line_count_after - line_count_before;
11255            } else if line_count_before > line_count_after {
11256                removed_lines += line_count_before - line_count_after;
11257            }
11258        }
11259
11260        self.transact(window, cx, |this, window, cx| {
11261            let buffer = this.buffer.update(cx, |buffer, cx| {
11262                buffer.edit(edits, None, cx);
11263                buffer.snapshot(cx)
11264            });
11265
11266            // Recalculate offsets on newly edited buffer
11267            let new_selections = new_selections
11268                .iter()
11269                .map(|s| {
11270                    let start_point = Point::new(s.start.0, 0);
11271                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11272                    Selection {
11273                        id: s.id,
11274                        start: buffer.point_to_offset(start_point),
11275                        end: buffer.point_to_offset(end_point),
11276                        goal: s.goal,
11277                        reversed: s.reversed,
11278                    }
11279                })
11280                .collect();
11281
11282            this.change_selections(Default::default(), window, cx, |s| {
11283                s.select(new_selections);
11284            });
11285
11286            this.request_autoscroll(Autoscroll::fit(), cx);
11287        });
11288    }
11289
11290    fn manipulate_immutable_lines<Fn>(
11291        &mut self,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294        mut callback: Fn,
11295    ) where
11296        Fn: FnMut(&mut Vec<&str>),
11297    {
11298        self.manipulate_lines(window, cx, |text| {
11299            let mut lines: Vec<&str> = text.split('\n').collect();
11300            let line_count_before = lines.len();
11301
11302            callback(&mut lines);
11303
11304            LineManipulationResult {
11305                new_text: lines.join("\n"),
11306                line_count_before,
11307                line_count_after: lines.len(),
11308            }
11309        });
11310    }
11311
11312    fn manipulate_mutable_lines<Fn>(
11313        &mut self,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316        mut callback: Fn,
11317    ) where
11318        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11319    {
11320        self.manipulate_lines(window, cx, |text| {
11321            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11322            let line_count_before = lines.len();
11323
11324            callback(&mut lines);
11325
11326            LineManipulationResult {
11327                new_text: lines.join("\n"),
11328                line_count_before,
11329                line_count_after: lines.len(),
11330            }
11331        });
11332    }
11333
11334    pub fn convert_indentation_to_spaces(
11335        &mut self,
11336        _: &ConvertIndentationToSpaces,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        let settings = self.buffer.read(cx).language_settings(cx);
11341        let tab_size = settings.tab_size.get() as usize;
11342
11343        self.manipulate_mutable_lines(window, cx, |lines| {
11344            // Allocates a reasonably sized scratch buffer once for the whole loop
11345            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11346            // Avoids recomputing spaces that could be inserted many times
11347            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11348                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11349                .collect();
11350
11351            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11352                let mut chars = line.as_ref().chars();
11353                let mut col = 0;
11354                let mut changed = false;
11355
11356                for ch in chars.by_ref() {
11357                    match ch {
11358                        ' ' => {
11359                            reindented_line.push(' ');
11360                            col += 1;
11361                        }
11362                        '\t' => {
11363                            // \t are converted to spaces depending on the current column
11364                            let spaces_len = tab_size - (col % tab_size);
11365                            reindented_line.extend(&space_cache[spaces_len - 1]);
11366                            col += spaces_len;
11367                            changed = true;
11368                        }
11369                        _ => {
11370                            // If we dont append before break, the character is consumed
11371                            reindented_line.push(ch);
11372                            break;
11373                        }
11374                    }
11375                }
11376
11377                if !changed {
11378                    reindented_line.clear();
11379                    continue;
11380                }
11381                // Append the rest of the line and replace old reference with new one
11382                reindented_line.extend(chars);
11383                *line = Cow::Owned(reindented_line.clone());
11384                reindented_line.clear();
11385            }
11386        });
11387    }
11388
11389    pub fn convert_indentation_to_tabs(
11390        &mut self,
11391        _: &ConvertIndentationToTabs,
11392        window: &mut Window,
11393        cx: &mut Context<Self>,
11394    ) {
11395        let settings = self.buffer.read(cx).language_settings(cx);
11396        let tab_size = settings.tab_size.get() as usize;
11397
11398        self.manipulate_mutable_lines(window, cx, |lines| {
11399            // Allocates a reasonably sized buffer once for the whole loop
11400            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11401            // Avoids recomputing spaces that could be inserted many times
11402            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11403                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11404                .collect();
11405
11406            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11407                let mut chars = line.chars();
11408                let mut spaces_count = 0;
11409                let mut first_non_indent_char = None;
11410                let mut changed = false;
11411
11412                for ch in chars.by_ref() {
11413                    match ch {
11414                        ' ' => {
11415                            // Keep track of spaces. Append \t when we reach tab_size
11416                            spaces_count += 1;
11417                            changed = true;
11418                            if spaces_count == tab_size {
11419                                reindented_line.push('\t');
11420                                spaces_count = 0;
11421                            }
11422                        }
11423                        '\t' => {
11424                            reindented_line.push('\t');
11425                            spaces_count = 0;
11426                        }
11427                        _ => {
11428                            // Dont append it yet, we might have remaining spaces
11429                            first_non_indent_char = Some(ch);
11430                            break;
11431                        }
11432                    }
11433                }
11434
11435                if !changed {
11436                    reindented_line.clear();
11437                    continue;
11438                }
11439                // Remaining spaces that didn't make a full tab stop
11440                if spaces_count > 0 {
11441                    reindented_line.extend(&space_cache[spaces_count - 1]);
11442                }
11443                // If we consume an extra character that was not indentation, add it back
11444                if let Some(extra_char) = first_non_indent_char {
11445                    reindented_line.push(extra_char);
11446                }
11447                // Append the rest of the line and replace old reference with new one
11448                reindented_line.extend(chars);
11449                *line = Cow::Owned(reindented_line.clone());
11450                reindented_line.clear();
11451            }
11452        });
11453    }
11454
11455    pub fn convert_to_upper_case(
11456        &mut self,
11457        _: &ConvertToUpperCase,
11458        window: &mut Window,
11459        cx: &mut Context<Self>,
11460    ) {
11461        self.manipulate_text(window, cx, |text| text.to_uppercase())
11462    }
11463
11464    pub fn convert_to_lower_case(
11465        &mut self,
11466        _: &ConvertToLowerCase,
11467        window: &mut Window,
11468        cx: &mut Context<Self>,
11469    ) {
11470        self.manipulate_text(window, cx, |text| text.to_lowercase())
11471    }
11472
11473    pub fn convert_to_title_case(
11474        &mut self,
11475        _: &ConvertToTitleCase,
11476        window: &mut Window,
11477        cx: &mut Context<Self>,
11478    ) {
11479        self.manipulate_text(window, cx, |text| {
11480            text.split('\n')
11481                .map(|line| line.to_case(Case::Title))
11482                .join("\n")
11483        })
11484    }
11485
11486    pub fn convert_to_snake_case(
11487        &mut self,
11488        _: &ConvertToSnakeCase,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11493    }
11494
11495    pub fn convert_to_kebab_case(
11496        &mut self,
11497        _: &ConvertToKebabCase,
11498        window: &mut Window,
11499        cx: &mut Context<Self>,
11500    ) {
11501        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11502    }
11503
11504    pub fn convert_to_upper_camel_case(
11505        &mut self,
11506        _: &ConvertToUpperCamelCase,
11507        window: &mut Window,
11508        cx: &mut Context<Self>,
11509    ) {
11510        self.manipulate_text(window, cx, |text| {
11511            text.split('\n')
11512                .map(|line| line.to_case(Case::UpperCamel))
11513                .join("\n")
11514        })
11515    }
11516
11517    pub fn convert_to_lower_camel_case(
11518        &mut self,
11519        _: &ConvertToLowerCamelCase,
11520        window: &mut Window,
11521        cx: &mut Context<Self>,
11522    ) {
11523        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11524    }
11525
11526    pub fn convert_to_opposite_case(
11527        &mut self,
11528        _: &ConvertToOppositeCase,
11529        window: &mut Window,
11530        cx: &mut Context<Self>,
11531    ) {
11532        self.manipulate_text(window, cx, |text| {
11533            text.chars()
11534                .fold(String::with_capacity(text.len()), |mut t, c| {
11535                    if c.is_uppercase() {
11536                        t.extend(c.to_lowercase());
11537                    } else {
11538                        t.extend(c.to_uppercase());
11539                    }
11540                    t
11541                })
11542        })
11543    }
11544
11545    pub fn convert_to_sentence_case(
11546        &mut self,
11547        _: &ConvertToSentenceCase,
11548        window: &mut Window,
11549        cx: &mut Context<Self>,
11550    ) {
11551        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11552    }
11553
11554    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11555        self.manipulate_text(window, cx, |text| {
11556            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11557            if has_upper_case_characters {
11558                text.to_lowercase()
11559            } else {
11560                text.to_uppercase()
11561            }
11562        })
11563    }
11564
11565    pub fn convert_to_rot13(
11566        &mut self,
11567        _: &ConvertToRot13,
11568        window: &mut Window,
11569        cx: &mut Context<Self>,
11570    ) {
11571        self.manipulate_text(window, cx, |text| {
11572            text.chars()
11573                .map(|c| match c {
11574                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11575                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11576                    _ => c,
11577                })
11578                .collect()
11579        })
11580    }
11581
11582    pub fn convert_to_rot47(
11583        &mut self,
11584        _: &ConvertToRot47,
11585        window: &mut Window,
11586        cx: &mut Context<Self>,
11587    ) {
11588        self.manipulate_text(window, cx, |text| {
11589            text.chars()
11590                .map(|c| {
11591                    let code_point = c as u32;
11592                    if code_point >= 33 && code_point <= 126 {
11593                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11594                    }
11595                    c
11596                })
11597                .collect()
11598        })
11599    }
11600
11601    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11602    where
11603        Fn: FnMut(&str) -> String,
11604    {
11605        let buffer = self.buffer.read(cx).snapshot(cx);
11606
11607        let mut new_selections = Vec::new();
11608        let mut edits = Vec::new();
11609        let mut selection_adjustment = 0i32;
11610
11611        for selection in self.selections.all_adjusted(cx) {
11612            let selection_is_empty = selection.is_empty();
11613
11614            let (start, end) = if selection_is_empty {
11615                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11616                (word_range.start, word_range.end)
11617            } else {
11618                (
11619                    buffer.point_to_offset(selection.start),
11620                    buffer.point_to_offset(selection.end),
11621                )
11622            };
11623
11624            let text = buffer.text_for_range(start..end).collect::<String>();
11625            let old_length = text.len() as i32;
11626            let text = callback(&text);
11627
11628            new_selections.push(Selection {
11629                start: (start as i32 - selection_adjustment) as usize,
11630                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11631                goal: SelectionGoal::None,
11632                id: selection.id,
11633                reversed: selection.reversed,
11634            });
11635
11636            selection_adjustment += old_length - text.len() as i32;
11637
11638            edits.push((start..end, text));
11639        }
11640
11641        self.transact(window, cx, |this, window, cx| {
11642            this.buffer.update(cx, |buffer, cx| {
11643                buffer.edit(edits, None, cx);
11644            });
11645
11646            this.change_selections(Default::default(), window, cx, |s| {
11647                s.select(new_selections);
11648            });
11649
11650            this.request_autoscroll(Autoscroll::fit(), cx);
11651        });
11652    }
11653
11654    pub fn move_selection_on_drop(
11655        &mut self,
11656        selection: &Selection<Anchor>,
11657        target: DisplayPoint,
11658        is_cut: bool,
11659        window: &mut Window,
11660        cx: &mut Context<Self>,
11661    ) {
11662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11663        let buffer = display_map.buffer_snapshot();
11664        let mut edits = Vec::new();
11665        let insert_point = display_map
11666            .clip_point(target, Bias::Left)
11667            .to_point(&display_map);
11668        let text = buffer
11669            .text_for_range(selection.start..selection.end)
11670            .collect::<String>();
11671        if is_cut {
11672            edits.push(((selection.start..selection.end), String::new()));
11673        }
11674        let insert_anchor = buffer.anchor_before(insert_point);
11675        edits.push(((insert_anchor..insert_anchor), text));
11676        let last_edit_start = insert_anchor.bias_left(buffer);
11677        let last_edit_end = insert_anchor.bias_right(buffer);
11678        self.transact(window, cx, |this, window, cx| {
11679            this.buffer.update(cx, |buffer, cx| {
11680                buffer.edit(edits, None, cx);
11681            });
11682            this.change_selections(Default::default(), window, cx, |s| {
11683                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11684            });
11685        });
11686    }
11687
11688    pub fn clear_selection_drag_state(&mut self) {
11689        self.selection_drag_state = SelectionDragState::None;
11690    }
11691
11692    pub fn duplicate(
11693        &mut self,
11694        upwards: bool,
11695        whole_lines: bool,
11696        window: &mut Window,
11697        cx: &mut Context<Self>,
11698    ) {
11699        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11700
11701        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11702        let buffer = display_map.buffer_snapshot();
11703        let selections = self.selections.all::<Point>(cx);
11704
11705        let mut edits = Vec::new();
11706        let mut selections_iter = selections.iter().peekable();
11707        while let Some(selection) = selections_iter.next() {
11708            let mut rows = selection.spanned_rows(false, &display_map);
11709            // duplicate line-wise
11710            if whole_lines || selection.start == selection.end {
11711                // Avoid duplicating the same lines twice.
11712                while let Some(next_selection) = selections_iter.peek() {
11713                    let next_rows = next_selection.spanned_rows(false, &display_map);
11714                    if next_rows.start < rows.end {
11715                        rows.end = next_rows.end;
11716                        selections_iter.next().unwrap();
11717                    } else {
11718                        break;
11719                    }
11720                }
11721
11722                // Copy the text from the selected row region and splice it either at the start
11723                // or end of the region.
11724                let start = Point::new(rows.start.0, 0);
11725                let end = Point::new(
11726                    rows.end.previous_row().0,
11727                    buffer.line_len(rows.end.previous_row()),
11728                );
11729
11730                let mut text = buffer.text_for_range(start..end).collect::<String>();
11731
11732                let insert_location = if upwards {
11733                    // When duplicating upward, we need to insert before the current line.
11734                    // If we're on the last line and it doesn't end with a newline,
11735                    // we need to add a newline before the duplicated content.
11736                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11737                        && buffer.max_point().column > 0
11738                        && !text.ends_with('\n');
11739
11740                    if needs_leading_newline {
11741                        text.insert(0, '\n');
11742                        end
11743                    } else {
11744                        text.push('\n');
11745                        Point::new(rows.end.0, 0)
11746                    }
11747                } else {
11748                    text.push('\n');
11749                    start
11750                };
11751                edits.push((insert_location..insert_location, text));
11752            } else {
11753                // duplicate character-wise
11754                let start = selection.start;
11755                let end = selection.end;
11756                let text = buffer.text_for_range(start..end).collect::<String>();
11757                edits.push((selection.end..selection.end, text));
11758            }
11759        }
11760
11761        self.transact(window, cx, |this, _, cx| {
11762            this.buffer.update(cx, |buffer, cx| {
11763                buffer.edit(edits, None, cx);
11764            });
11765
11766            this.request_autoscroll(Autoscroll::fit(), cx);
11767        });
11768    }
11769
11770    pub fn duplicate_line_up(
11771        &mut self,
11772        _: &DuplicateLineUp,
11773        window: &mut Window,
11774        cx: &mut Context<Self>,
11775    ) {
11776        self.duplicate(true, true, window, cx);
11777    }
11778
11779    pub fn duplicate_line_down(
11780        &mut self,
11781        _: &DuplicateLineDown,
11782        window: &mut Window,
11783        cx: &mut Context<Self>,
11784    ) {
11785        self.duplicate(false, true, window, cx);
11786    }
11787
11788    pub fn duplicate_selection(
11789        &mut self,
11790        _: &DuplicateSelection,
11791        window: &mut Window,
11792        cx: &mut Context<Self>,
11793    ) {
11794        self.duplicate(false, false, window, cx);
11795    }
11796
11797    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11798        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11799        if self.mode.is_single_line() {
11800            cx.propagate();
11801            return;
11802        }
11803
11804        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11805        let buffer = self.buffer.read(cx).snapshot(cx);
11806
11807        let mut edits = Vec::new();
11808        let mut unfold_ranges = Vec::new();
11809        let mut refold_creases = Vec::new();
11810
11811        let selections = self.selections.all::<Point>(cx);
11812        let mut selections = selections.iter().peekable();
11813        let mut contiguous_row_selections = Vec::new();
11814        let mut new_selections = Vec::new();
11815
11816        while let Some(selection) = selections.next() {
11817            // Find all the selections that span a contiguous row range
11818            let (start_row, end_row) = consume_contiguous_rows(
11819                &mut contiguous_row_selections,
11820                selection,
11821                &display_map,
11822                &mut selections,
11823            );
11824
11825            // Move the text spanned by the row range to be before the line preceding the row range
11826            if start_row.0 > 0 {
11827                let range_to_move = Point::new(
11828                    start_row.previous_row().0,
11829                    buffer.line_len(start_row.previous_row()),
11830                )
11831                    ..Point::new(
11832                        end_row.previous_row().0,
11833                        buffer.line_len(end_row.previous_row()),
11834                    );
11835                let insertion_point = display_map
11836                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11837                    .0;
11838
11839                // Don't move lines across excerpts
11840                if buffer
11841                    .excerpt_containing(insertion_point..range_to_move.end)
11842                    .is_some()
11843                {
11844                    let text = buffer
11845                        .text_for_range(range_to_move.clone())
11846                        .flat_map(|s| s.chars())
11847                        .skip(1)
11848                        .chain(['\n'])
11849                        .collect::<String>();
11850
11851                    edits.push((
11852                        buffer.anchor_after(range_to_move.start)
11853                            ..buffer.anchor_before(range_to_move.end),
11854                        String::new(),
11855                    ));
11856                    let insertion_anchor = buffer.anchor_after(insertion_point);
11857                    edits.push((insertion_anchor..insertion_anchor, text));
11858
11859                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11860
11861                    // Move selections up
11862                    new_selections.extend(contiguous_row_selections.drain(..).map(
11863                        |mut selection| {
11864                            selection.start.row -= row_delta;
11865                            selection.end.row -= row_delta;
11866                            selection
11867                        },
11868                    ));
11869
11870                    // Move folds up
11871                    unfold_ranges.push(range_to_move.clone());
11872                    for fold in display_map.folds_in_range(
11873                        buffer.anchor_before(range_to_move.start)
11874                            ..buffer.anchor_after(range_to_move.end),
11875                    ) {
11876                        let mut start = fold.range.start.to_point(&buffer);
11877                        let mut end = fold.range.end.to_point(&buffer);
11878                        start.row -= row_delta;
11879                        end.row -= row_delta;
11880                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11881                    }
11882                }
11883            }
11884
11885            // If we didn't move line(s), preserve the existing selections
11886            new_selections.append(&mut contiguous_row_selections);
11887        }
11888
11889        self.transact(window, cx, |this, window, cx| {
11890            this.unfold_ranges(&unfold_ranges, true, true, cx);
11891            this.buffer.update(cx, |buffer, cx| {
11892                for (range, text) in edits {
11893                    buffer.edit([(range, text)], None, cx);
11894                }
11895            });
11896            this.fold_creases(refold_creases, true, window, cx);
11897            this.change_selections(Default::default(), window, cx, |s| {
11898                s.select(new_selections);
11899            })
11900        });
11901    }
11902
11903    pub fn move_line_down(
11904        &mut self,
11905        _: &MoveLineDown,
11906        window: &mut Window,
11907        cx: &mut Context<Self>,
11908    ) {
11909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11910        if self.mode.is_single_line() {
11911            cx.propagate();
11912            return;
11913        }
11914
11915        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11916        let buffer = self.buffer.read(cx).snapshot(cx);
11917
11918        let mut edits = Vec::new();
11919        let mut unfold_ranges = Vec::new();
11920        let mut refold_creases = Vec::new();
11921
11922        let selections = self.selections.all::<Point>(cx);
11923        let mut selections = selections.iter().peekable();
11924        let mut contiguous_row_selections = Vec::new();
11925        let mut new_selections = Vec::new();
11926
11927        while let Some(selection) = selections.next() {
11928            // Find all the selections that span a contiguous row range
11929            let (start_row, end_row) = consume_contiguous_rows(
11930                &mut contiguous_row_selections,
11931                selection,
11932                &display_map,
11933                &mut selections,
11934            );
11935
11936            // Move the text spanned by the row range to be after the last line of the row range
11937            if end_row.0 <= buffer.max_point().row {
11938                let range_to_move =
11939                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11940                let insertion_point = display_map
11941                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11942                    .0;
11943
11944                // Don't move lines across excerpt boundaries
11945                if buffer
11946                    .excerpt_containing(range_to_move.start..insertion_point)
11947                    .is_some()
11948                {
11949                    let mut text = String::from("\n");
11950                    text.extend(buffer.text_for_range(range_to_move.clone()));
11951                    text.pop(); // Drop trailing newline
11952                    edits.push((
11953                        buffer.anchor_after(range_to_move.start)
11954                            ..buffer.anchor_before(range_to_move.end),
11955                        String::new(),
11956                    ));
11957                    let insertion_anchor = buffer.anchor_after(insertion_point);
11958                    edits.push((insertion_anchor..insertion_anchor, text));
11959
11960                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11961
11962                    // Move selections down
11963                    new_selections.extend(contiguous_row_selections.drain(..).map(
11964                        |mut selection| {
11965                            selection.start.row += row_delta;
11966                            selection.end.row += row_delta;
11967                            selection
11968                        },
11969                    ));
11970
11971                    // Move folds down
11972                    unfold_ranges.push(range_to_move.clone());
11973                    for fold in display_map.folds_in_range(
11974                        buffer.anchor_before(range_to_move.start)
11975                            ..buffer.anchor_after(range_to_move.end),
11976                    ) {
11977                        let mut start = fold.range.start.to_point(&buffer);
11978                        let mut end = fold.range.end.to_point(&buffer);
11979                        start.row += row_delta;
11980                        end.row += row_delta;
11981                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11982                    }
11983                }
11984            }
11985
11986            // If we didn't move line(s), preserve the existing selections
11987            new_selections.append(&mut contiguous_row_selections);
11988        }
11989
11990        self.transact(window, cx, |this, window, cx| {
11991            this.unfold_ranges(&unfold_ranges, true, true, cx);
11992            this.buffer.update(cx, |buffer, cx| {
11993                for (range, text) in edits {
11994                    buffer.edit([(range, text)], None, cx);
11995                }
11996            });
11997            this.fold_creases(refold_creases, true, window, cx);
11998            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11999        });
12000    }
12001
12002    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12003        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12004        let text_layout_details = &self.text_layout_details(window);
12005        self.transact(window, cx, |this, window, cx| {
12006            let edits = this.change_selections(Default::default(), window, cx, |s| {
12007                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12008                s.move_with(|display_map, selection| {
12009                    if !selection.is_empty() {
12010                        return;
12011                    }
12012
12013                    let mut head = selection.head();
12014                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12015                    if head.column() == display_map.line_len(head.row()) {
12016                        transpose_offset = display_map
12017                            .buffer_snapshot()
12018                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12019                    }
12020
12021                    if transpose_offset == 0 {
12022                        return;
12023                    }
12024
12025                    *head.column_mut() += 1;
12026                    head = display_map.clip_point(head, Bias::Right);
12027                    let goal = SelectionGoal::HorizontalPosition(
12028                        display_map
12029                            .x_for_display_point(head, text_layout_details)
12030                            .into(),
12031                    );
12032                    selection.collapse_to(head, goal);
12033
12034                    let transpose_start = display_map
12035                        .buffer_snapshot()
12036                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12037                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12038                        let transpose_end = display_map
12039                            .buffer_snapshot()
12040                            .clip_offset(transpose_offset + 1, Bias::Right);
12041                        if let Some(ch) = display_map
12042                            .buffer_snapshot()
12043                            .chars_at(transpose_start)
12044                            .next()
12045                        {
12046                            edits.push((transpose_start..transpose_offset, String::new()));
12047                            edits.push((transpose_end..transpose_end, ch.to_string()));
12048                        }
12049                    }
12050                });
12051                edits
12052            });
12053            this.buffer
12054                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12055            let selections = this.selections.all::<usize>(cx);
12056            this.change_selections(Default::default(), window, cx, |s| {
12057                s.select(selections);
12058            });
12059        });
12060    }
12061
12062    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12064        if self.mode.is_single_line() {
12065            cx.propagate();
12066            return;
12067        }
12068
12069        self.rewrap_impl(RewrapOptions::default(), cx)
12070    }
12071
12072    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12073        let buffer = self.buffer.read(cx).snapshot(cx);
12074        let selections = self.selections.all::<Point>(cx);
12075
12076        #[derive(Clone, Debug, PartialEq)]
12077        enum CommentFormat {
12078            /// single line comment, with prefix for line
12079            Line(String),
12080            /// single line within a block comment, with prefix for line
12081            BlockLine(String),
12082            /// a single line of a block comment that includes the initial delimiter
12083            BlockCommentWithStart(BlockCommentConfig),
12084            /// a single line of a block comment that includes the ending delimiter
12085            BlockCommentWithEnd(BlockCommentConfig),
12086        }
12087
12088        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12089        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12090            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12091                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12092                .peekable();
12093
12094            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12095                row
12096            } else {
12097                return Vec::new();
12098            };
12099
12100            let language_settings = buffer.language_settings_at(selection.head(), cx);
12101            let language_scope = buffer.language_scope_at(selection.head());
12102
12103            let indent_and_prefix_for_row =
12104                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12105                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12106                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12107                        &language_scope
12108                    {
12109                        let indent_end = Point::new(row, indent.len);
12110                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12111                        let line_text_after_indent = buffer
12112                            .text_for_range(indent_end..line_end)
12113                            .collect::<String>();
12114
12115                        let is_within_comment_override = buffer
12116                            .language_scope_at(indent_end)
12117                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12118                        let comment_delimiters = if is_within_comment_override {
12119                            // we are within a comment syntax node, but we don't
12120                            // yet know what kind of comment: block, doc or line
12121                            match (
12122                                language_scope.documentation_comment(),
12123                                language_scope.block_comment(),
12124                            ) {
12125                                (Some(config), _) | (_, Some(config))
12126                                    if buffer.contains_str_at(indent_end, &config.start) =>
12127                                {
12128                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12129                                }
12130                                (Some(config), _) | (_, Some(config))
12131                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12132                                {
12133                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12134                                }
12135                                (Some(config), _) | (_, Some(config))
12136                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12137                                {
12138                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12139                                }
12140                                (_, _) => language_scope
12141                                    .line_comment_prefixes()
12142                                    .iter()
12143                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12144                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12145                            }
12146                        } else {
12147                            // we not in an overridden comment node, but we may
12148                            // be within a non-overridden line comment node
12149                            language_scope
12150                                .line_comment_prefixes()
12151                                .iter()
12152                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12153                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12154                        };
12155
12156                        let rewrap_prefix = language_scope
12157                            .rewrap_prefixes()
12158                            .iter()
12159                            .find_map(|prefix_regex| {
12160                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12161                                    if mat.start() == 0 {
12162                                        Some(mat.as_str().to_string())
12163                                    } else {
12164                                        None
12165                                    }
12166                                })
12167                            })
12168                            .flatten();
12169                        (comment_delimiters, rewrap_prefix)
12170                    } else {
12171                        (None, None)
12172                    };
12173                    (indent, comment_prefix, rewrap_prefix)
12174                };
12175
12176            let mut ranges = Vec::new();
12177            let from_empty_selection = selection.is_empty();
12178
12179            let mut current_range_start = first_row;
12180            let mut prev_row = first_row;
12181            let (
12182                mut current_range_indent,
12183                mut current_range_comment_delimiters,
12184                mut current_range_rewrap_prefix,
12185            ) = indent_and_prefix_for_row(first_row);
12186
12187            for row in non_blank_rows_iter.skip(1) {
12188                let has_paragraph_break = row > prev_row + 1;
12189
12190                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12191                    indent_and_prefix_for_row(row);
12192
12193                let has_indent_change = row_indent != current_range_indent;
12194                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12195
12196                let has_boundary_change = has_comment_change
12197                    || row_rewrap_prefix.is_some()
12198                    || (has_indent_change && current_range_comment_delimiters.is_some());
12199
12200                if has_paragraph_break || has_boundary_change {
12201                    ranges.push((
12202                        language_settings.clone(),
12203                        Point::new(current_range_start, 0)
12204                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12205                        current_range_indent,
12206                        current_range_comment_delimiters.clone(),
12207                        current_range_rewrap_prefix.clone(),
12208                        from_empty_selection,
12209                    ));
12210                    current_range_start = row;
12211                    current_range_indent = row_indent;
12212                    current_range_comment_delimiters = row_comment_delimiters;
12213                    current_range_rewrap_prefix = row_rewrap_prefix;
12214                }
12215                prev_row = row;
12216            }
12217
12218            ranges.push((
12219                language_settings.clone(),
12220                Point::new(current_range_start, 0)
12221                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12222                current_range_indent,
12223                current_range_comment_delimiters,
12224                current_range_rewrap_prefix,
12225                from_empty_selection,
12226            ));
12227
12228            ranges
12229        });
12230
12231        let mut edits = Vec::new();
12232        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12233
12234        for (
12235            language_settings,
12236            wrap_range,
12237            mut indent_size,
12238            comment_prefix,
12239            rewrap_prefix,
12240            from_empty_selection,
12241        ) in wrap_ranges
12242        {
12243            let mut start_row = wrap_range.start.row;
12244            let mut end_row = wrap_range.end.row;
12245
12246            // Skip selections that overlap with a range that has already been rewrapped.
12247            let selection_range = start_row..end_row;
12248            if rewrapped_row_ranges
12249                .iter()
12250                .any(|range| range.overlaps(&selection_range))
12251            {
12252                continue;
12253            }
12254
12255            let tab_size = language_settings.tab_size;
12256
12257            let (line_prefix, inside_comment) = match &comment_prefix {
12258                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12259                    (Some(prefix.as_str()), true)
12260                }
12261                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12262                    (Some(prefix.as_ref()), true)
12263                }
12264                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12265                    start: _,
12266                    end: _,
12267                    prefix,
12268                    tab_size,
12269                })) => {
12270                    indent_size.len += tab_size;
12271                    (Some(prefix.as_ref()), true)
12272                }
12273                None => (None, false),
12274            };
12275            let indent_prefix = indent_size.chars().collect::<String>();
12276            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12277
12278            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12279                RewrapBehavior::InComments => inside_comment,
12280                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12281                RewrapBehavior::Anywhere => true,
12282            };
12283
12284            let should_rewrap = options.override_language_settings
12285                || allow_rewrap_based_on_language
12286                || self.hard_wrap.is_some();
12287            if !should_rewrap {
12288                continue;
12289            }
12290
12291            if from_empty_selection {
12292                'expand_upwards: while start_row > 0 {
12293                    let prev_row = start_row - 1;
12294                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12295                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12296                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12297                    {
12298                        start_row = prev_row;
12299                    } else {
12300                        break 'expand_upwards;
12301                    }
12302                }
12303
12304                'expand_downwards: while end_row < buffer.max_point().row {
12305                    let next_row = end_row + 1;
12306                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12307                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12308                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12309                    {
12310                        end_row = next_row;
12311                    } else {
12312                        break 'expand_downwards;
12313                    }
12314                }
12315            }
12316
12317            let start = Point::new(start_row, 0);
12318            let start_offset = ToOffset::to_offset(&start, &buffer);
12319            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12320            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12321            let mut first_line_delimiter = None;
12322            let mut last_line_delimiter = None;
12323            let Some(lines_without_prefixes) = selection_text
12324                .lines()
12325                .enumerate()
12326                .map(|(ix, line)| {
12327                    let line_trimmed = line.trim_start();
12328                    if rewrap_prefix.is_some() && ix > 0 {
12329                        Ok(line_trimmed)
12330                    } else if let Some(
12331                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12332                            start,
12333                            prefix,
12334                            end,
12335                            tab_size,
12336                        })
12337                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12338                            start,
12339                            prefix,
12340                            end,
12341                            tab_size,
12342                        }),
12343                    ) = &comment_prefix
12344                    {
12345                        let line_trimmed = line_trimmed
12346                            .strip_prefix(start.as_ref())
12347                            .map(|s| {
12348                                let mut indent_size = indent_size;
12349                                indent_size.len -= tab_size;
12350                                let indent_prefix: String = indent_size.chars().collect();
12351                                first_line_delimiter = Some((indent_prefix, start));
12352                                s.trim_start()
12353                            })
12354                            .unwrap_or(line_trimmed);
12355                        let line_trimmed = line_trimmed
12356                            .strip_suffix(end.as_ref())
12357                            .map(|s| {
12358                                last_line_delimiter = Some(end);
12359                                s.trim_end()
12360                            })
12361                            .unwrap_or(line_trimmed);
12362                        let line_trimmed = line_trimmed
12363                            .strip_prefix(prefix.as_ref())
12364                            .unwrap_or(line_trimmed);
12365                        Ok(line_trimmed)
12366                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12367                        line_trimmed.strip_prefix(prefix).with_context(|| {
12368                            format!("line did not start with prefix {prefix:?}: {line:?}")
12369                        })
12370                    } else {
12371                        line_trimmed
12372                            .strip_prefix(&line_prefix.trim_start())
12373                            .with_context(|| {
12374                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12375                            })
12376                    }
12377                })
12378                .collect::<Result<Vec<_>, _>>()
12379                .log_err()
12380            else {
12381                continue;
12382            };
12383
12384            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12385                buffer
12386                    .language_settings_at(Point::new(start_row, 0), cx)
12387                    .preferred_line_length as usize
12388            });
12389
12390            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12391                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12392            } else {
12393                line_prefix.clone()
12394            };
12395
12396            let wrapped_text = {
12397                let mut wrapped_text = wrap_with_prefix(
12398                    line_prefix,
12399                    subsequent_lines_prefix,
12400                    lines_without_prefixes.join("\n"),
12401                    wrap_column,
12402                    tab_size,
12403                    options.preserve_existing_whitespace,
12404                );
12405
12406                if let Some((indent, delimiter)) = first_line_delimiter {
12407                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12408                }
12409                if let Some(last_line) = last_line_delimiter {
12410                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12411                }
12412
12413                wrapped_text
12414            };
12415
12416            // TODO: should always use char-based diff while still supporting cursor behavior that
12417            // matches vim.
12418            let mut diff_options = DiffOptions::default();
12419            if options.override_language_settings {
12420                diff_options.max_word_diff_len = 0;
12421                diff_options.max_word_diff_line_count = 0;
12422            } else {
12423                diff_options.max_word_diff_len = usize::MAX;
12424                diff_options.max_word_diff_line_count = usize::MAX;
12425            }
12426
12427            for (old_range, new_text) in
12428                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12429            {
12430                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12431                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12432                edits.push((edit_start..edit_end, new_text));
12433            }
12434
12435            rewrapped_row_ranges.push(start_row..=end_row);
12436        }
12437
12438        self.buffer
12439            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12440    }
12441
12442    pub fn cut_common(
12443        &mut self,
12444        cut_no_selection_line: bool,
12445        window: &mut Window,
12446        cx: &mut Context<Self>,
12447    ) -> ClipboardItem {
12448        let mut text = String::new();
12449        let buffer = self.buffer.read(cx).snapshot(cx);
12450        let mut selections = self.selections.all::<Point>(cx);
12451        let mut clipboard_selections = Vec::with_capacity(selections.len());
12452        {
12453            let max_point = buffer.max_point();
12454            let mut is_first = true;
12455            for selection in &mut selections {
12456                let is_entire_line =
12457                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12458                if is_entire_line {
12459                    selection.start = Point::new(selection.start.row, 0);
12460                    if !selection.is_empty() && selection.end.column == 0 {
12461                        selection.end = cmp::min(max_point, selection.end);
12462                    } else {
12463                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12464                    }
12465                    selection.goal = SelectionGoal::None;
12466                }
12467                if is_first {
12468                    is_first = false;
12469                } else {
12470                    text += "\n";
12471                }
12472                let mut len = 0;
12473                for chunk in buffer.text_for_range(selection.start..selection.end) {
12474                    text.push_str(chunk);
12475                    len += chunk.len();
12476                }
12477                clipboard_selections.push(ClipboardSelection {
12478                    len,
12479                    is_entire_line,
12480                    first_line_indent: buffer
12481                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12482                        .len,
12483                });
12484            }
12485        }
12486
12487        self.transact(window, cx, |this, window, cx| {
12488            this.change_selections(Default::default(), window, cx, |s| {
12489                s.select(selections);
12490            });
12491            this.insert("", window, cx);
12492        });
12493        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12494    }
12495
12496    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12497        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12498        let item = self.cut_common(true, window, cx);
12499        cx.write_to_clipboard(item);
12500    }
12501
12502    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12503        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12504        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12505            s.move_with(|snapshot, sel| {
12506                if sel.is_empty() {
12507                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12508                }
12509                if sel.is_empty() {
12510                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12511                }
12512            });
12513        });
12514        let item = self.cut_common(false, window, cx);
12515        cx.set_global(KillRing(item))
12516    }
12517
12518    pub fn kill_ring_yank(
12519        &mut self,
12520        _: &KillRingYank,
12521        window: &mut Window,
12522        cx: &mut Context<Self>,
12523    ) {
12524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12525        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12526            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12527                (kill_ring.text().to_string(), kill_ring.metadata_json())
12528            } else {
12529                return;
12530            }
12531        } else {
12532            return;
12533        };
12534        self.do_paste(&text, metadata, false, window, cx);
12535    }
12536
12537    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12538        self.do_copy(true, cx);
12539    }
12540
12541    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12542        self.do_copy(false, cx);
12543    }
12544
12545    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12546        let selections = self.selections.all::<Point>(cx);
12547        let buffer = self.buffer.read(cx).read(cx);
12548        let mut text = String::new();
12549
12550        let mut clipboard_selections = Vec::with_capacity(selections.len());
12551        {
12552            let max_point = buffer.max_point();
12553            let mut is_first = true;
12554            for selection in &selections {
12555                let mut start = selection.start;
12556                let mut end = selection.end;
12557                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12558                let mut add_trailing_newline = false;
12559                if is_entire_line {
12560                    start = Point::new(start.row, 0);
12561                    let next_line_start = Point::new(end.row + 1, 0);
12562                    if next_line_start <= max_point {
12563                        end = next_line_start;
12564                    } else {
12565                        // We're on the last line without a trailing newline.
12566                        // Copy to the end of the line and add a newline afterwards.
12567                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12568                        add_trailing_newline = true;
12569                    }
12570                }
12571
12572                let mut trimmed_selections = Vec::new();
12573                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12574                    let row = MultiBufferRow(start.row);
12575                    let first_indent = buffer.indent_size_for_line(row);
12576                    if first_indent.len == 0 || start.column > first_indent.len {
12577                        trimmed_selections.push(start..end);
12578                    } else {
12579                        trimmed_selections.push(
12580                            Point::new(row.0, first_indent.len)
12581                                ..Point::new(row.0, buffer.line_len(row)),
12582                        );
12583                        for row in start.row + 1..=end.row {
12584                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12585                            if row == end.row {
12586                                line_len = end.column;
12587                            }
12588                            if line_len == 0 {
12589                                trimmed_selections
12590                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12591                                continue;
12592                            }
12593                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12594                            if row_indent_size.len >= first_indent.len {
12595                                trimmed_selections.push(
12596                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12597                                );
12598                            } else {
12599                                trimmed_selections.clear();
12600                                trimmed_selections.push(start..end);
12601                                break;
12602                            }
12603                        }
12604                    }
12605                } else {
12606                    trimmed_selections.push(start..end);
12607                }
12608
12609                for trimmed_range in trimmed_selections {
12610                    if is_first {
12611                        is_first = false;
12612                    } else {
12613                        text += "\n";
12614                    }
12615                    let mut len = 0;
12616                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12617                        text.push_str(chunk);
12618                        len += chunk.len();
12619                    }
12620                    if add_trailing_newline {
12621                        text.push('\n');
12622                        len += 1;
12623                    }
12624                    clipboard_selections.push(ClipboardSelection {
12625                        len,
12626                        is_entire_line,
12627                        first_line_indent: buffer
12628                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12629                            .len,
12630                    });
12631                }
12632            }
12633        }
12634
12635        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12636            text,
12637            clipboard_selections,
12638        ));
12639    }
12640
12641    pub fn do_paste(
12642        &mut self,
12643        text: &String,
12644        clipboard_selections: Option<Vec<ClipboardSelection>>,
12645        handle_entire_lines: bool,
12646        window: &mut Window,
12647        cx: &mut Context<Self>,
12648    ) {
12649        if self.read_only(cx) {
12650            return;
12651        }
12652
12653        let clipboard_text = Cow::Borrowed(text.as_str());
12654
12655        self.transact(window, cx, |this, window, cx| {
12656            let had_active_edit_prediction = this.has_active_edit_prediction();
12657            let old_selections = this.selections.all::<usize>(cx);
12658            let cursor_offset = this.selections.last::<usize>(cx).head();
12659
12660            if let Some(mut clipboard_selections) = clipboard_selections {
12661                let all_selections_were_entire_line =
12662                    clipboard_selections.iter().all(|s| s.is_entire_line);
12663                let first_selection_indent_column =
12664                    clipboard_selections.first().map(|s| s.first_line_indent);
12665                if clipboard_selections.len() != old_selections.len() {
12666                    clipboard_selections.drain(..);
12667                }
12668                let mut auto_indent_on_paste = true;
12669
12670                this.buffer.update(cx, |buffer, cx| {
12671                    let snapshot = buffer.read(cx);
12672                    auto_indent_on_paste = snapshot
12673                        .language_settings_at(cursor_offset, cx)
12674                        .auto_indent_on_paste;
12675
12676                    let mut start_offset = 0;
12677                    let mut edits = Vec::new();
12678                    let mut original_indent_columns = Vec::new();
12679                    for (ix, selection) in old_selections.iter().enumerate() {
12680                        let to_insert;
12681                        let entire_line;
12682                        let original_indent_column;
12683                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12684                            let end_offset = start_offset + clipboard_selection.len;
12685                            to_insert = &clipboard_text[start_offset..end_offset];
12686                            entire_line = clipboard_selection.is_entire_line;
12687                            start_offset = end_offset + 1;
12688                            original_indent_column = Some(clipboard_selection.first_line_indent);
12689                        } else {
12690                            to_insert = &*clipboard_text;
12691                            entire_line = all_selections_were_entire_line;
12692                            original_indent_column = first_selection_indent_column
12693                        }
12694
12695                        let (range, to_insert) =
12696                            if selection.is_empty() && handle_entire_lines && entire_line {
12697                                // If the corresponding selection was empty when this slice of the
12698                                // clipboard text was written, then the entire line containing the
12699                                // selection was copied. If this selection is also currently empty,
12700                                // then paste the line before the current line of the buffer.
12701                                let column = selection.start.to_point(&snapshot).column as usize;
12702                                let line_start = selection.start - column;
12703                                (line_start..line_start, Cow::Borrowed(to_insert))
12704                            } else {
12705                                let language = snapshot.language_at(selection.head());
12706                                let range = selection.range();
12707                                if let Some(language) = language
12708                                    && language.name() == "Markdown".into()
12709                                {
12710                                    edit_for_markdown_paste(
12711                                        &snapshot,
12712                                        range,
12713                                        to_insert,
12714                                        url::Url::parse(to_insert).ok(),
12715                                    )
12716                                } else {
12717                                    (range, Cow::Borrowed(to_insert))
12718                                }
12719                            };
12720
12721                        edits.push((range, to_insert));
12722                        original_indent_columns.push(original_indent_column);
12723                    }
12724                    drop(snapshot);
12725
12726                    buffer.edit(
12727                        edits,
12728                        if auto_indent_on_paste {
12729                            Some(AutoindentMode::Block {
12730                                original_indent_columns,
12731                            })
12732                        } else {
12733                            None
12734                        },
12735                        cx,
12736                    );
12737                });
12738
12739                let selections = this.selections.all::<usize>(cx);
12740                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12741            } else {
12742                let url = url::Url::parse(&clipboard_text).ok();
12743
12744                let auto_indent_mode = if !clipboard_text.is_empty() {
12745                    Some(AutoindentMode::Block {
12746                        original_indent_columns: Vec::new(),
12747                    })
12748                } else {
12749                    None
12750                };
12751
12752                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12753                    let snapshot = buffer.snapshot(cx);
12754
12755                    let anchors = old_selections
12756                        .iter()
12757                        .map(|s| {
12758                            let anchor = snapshot.anchor_after(s.head());
12759                            s.map(|_| anchor)
12760                        })
12761                        .collect::<Vec<_>>();
12762
12763                    let mut edits = Vec::new();
12764
12765                    for selection in old_selections.iter() {
12766                        let language = snapshot.language_at(selection.head());
12767                        let range = selection.range();
12768
12769                        let (edit_range, edit_text) = if let Some(language) = language
12770                            && language.name() == "Markdown".into()
12771                        {
12772                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12773                        } else {
12774                            (range, clipboard_text.clone())
12775                        };
12776
12777                        edits.push((edit_range, edit_text));
12778                    }
12779
12780                    drop(snapshot);
12781                    buffer.edit(edits, auto_indent_mode, cx);
12782
12783                    anchors
12784                });
12785
12786                this.change_selections(Default::default(), window, cx, |s| {
12787                    s.select_anchors(selection_anchors);
12788                });
12789            }
12790
12791            let trigger_in_words =
12792                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12793
12794            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12795        });
12796    }
12797
12798    pub fn diff_clipboard_with_selection(
12799        &mut self,
12800        _: &DiffClipboardWithSelection,
12801        window: &mut Window,
12802        cx: &mut Context<Self>,
12803    ) {
12804        let selections = self.selections.all::<usize>(cx);
12805
12806        if selections.is_empty() {
12807            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12808            return;
12809        };
12810
12811        let clipboard_text = match cx.read_from_clipboard() {
12812            Some(item) => match item.entries().first() {
12813                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12814                _ => None,
12815            },
12816            None => None,
12817        };
12818
12819        let Some(clipboard_text) = clipboard_text else {
12820            log::warn!("Clipboard doesn't contain text.");
12821            return;
12822        };
12823
12824        window.dispatch_action(
12825            Box::new(DiffClipboardWithSelectionData {
12826                clipboard_text,
12827                editor: cx.entity(),
12828            }),
12829            cx,
12830        );
12831    }
12832
12833    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12835        if let Some(item) = cx.read_from_clipboard() {
12836            let entries = item.entries();
12837
12838            match entries.first() {
12839                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12840                // of all the pasted entries.
12841                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12842                    .do_paste(
12843                        clipboard_string.text(),
12844                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12845                        true,
12846                        window,
12847                        cx,
12848                    ),
12849                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12850            }
12851        }
12852    }
12853
12854    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12855        if self.read_only(cx) {
12856            return;
12857        }
12858
12859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12860
12861        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12862            if let Some((selections, _)) =
12863                self.selection_history.transaction(transaction_id).cloned()
12864            {
12865                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12866                    s.select_anchors(selections.to_vec());
12867                });
12868            } else {
12869                log::error!(
12870                    "No entry in selection_history found for undo. \
12871                     This may correspond to a bug where undo does not update the selection. \
12872                     If this is occurring, please add details to \
12873                     https://github.com/zed-industries/zed/issues/22692"
12874                );
12875            }
12876            self.request_autoscroll(Autoscroll::fit(), cx);
12877            self.unmark_text(window, cx);
12878            self.refresh_edit_prediction(true, false, window, cx);
12879            cx.emit(EditorEvent::Edited { transaction_id });
12880            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12881        }
12882    }
12883
12884    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12885        if self.read_only(cx) {
12886            return;
12887        }
12888
12889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12890
12891        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12892            if let Some((_, Some(selections))) =
12893                self.selection_history.transaction(transaction_id).cloned()
12894            {
12895                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12896                    s.select_anchors(selections.to_vec());
12897                });
12898            } else {
12899                log::error!(
12900                    "No entry in selection_history found for redo. \
12901                     This may correspond to a bug where undo does not update the selection. \
12902                     If this is occurring, please add details to \
12903                     https://github.com/zed-industries/zed/issues/22692"
12904                );
12905            }
12906            self.request_autoscroll(Autoscroll::fit(), cx);
12907            self.unmark_text(window, cx);
12908            self.refresh_edit_prediction(true, false, window, cx);
12909            cx.emit(EditorEvent::Edited { transaction_id });
12910        }
12911    }
12912
12913    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12914        self.buffer
12915            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12916    }
12917
12918    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12919        self.buffer
12920            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12921    }
12922
12923    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12924        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12925        self.change_selections(Default::default(), window, cx, |s| {
12926            s.move_with(|map, selection| {
12927                let cursor = if selection.is_empty() {
12928                    movement::left(map, selection.start)
12929                } else {
12930                    selection.start
12931                };
12932                selection.collapse_to(cursor, SelectionGoal::None);
12933            });
12934        })
12935    }
12936
12937    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12939        self.change_selections(Default::default(), window, cx, |s| {
12940            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12941        })
12942    }
12943
12944    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12946        self.change_selections(Default::default(), window, cx, |s| {
12947            s.move_with(|map, selection| {
12948                let cursor = if selection.is_empty() {
12949                    movement::right(map, selection.end)
12950                } else {
12951                    selection.end
12952                };
12953                selection.collapse_to(cursor, SelectionGoal::None)
12954            });
12955        })
12956    }
12957
12958    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12960        self.change_selections(Default::default(), window, cx, |s| {
12961            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12962        });
12963    }
12964
12965    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12966        if self.take_rename(true, window, cx).is_some() {
12967            return;
12968        }
12969
12970        if self.mode.is_single_line() {
12971            cx.propagate();
12972            return;
12973        }
12974
12975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12976
12977        let text_layout_details = &self.text_layout_details(window);
12978        let selection_count = self.selections.count();
12979        let first_selection = self.selections.first_anchor();
12980
12981        self.change_selections(Default::default(), window, cx, |s| {
12982            s.move_with(|map, selection| {
12983                if !selection.is_empty() {
12984                    selection.goal = SelectionGoal::None;
12985                }
12986                let (cursor, goal) = movement::up(
12987                    map,
12988                    selection.start,
12989                    selection.goal,
12990                    false,
12991                    text_layout_details,
12992                );
12993                selection.collapse_to(cursor, goal);
12994            });
12995        });
12996
12997        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12998        {
12999            cx.propagate();
13000        }
13001    }
13002
13003    pub fn move_up_by_lines(
13004        &mut self,
13005        action: &MoveUpByLines,
13006        window: &mut Window,
13007        cx: &mut Context<Self>,
13008    ) {
13009        if self.take_rename(true, window, cx).is_some() {
13010            return;
13011        }
13012
13013        if self.mode.is_single_line() {
13014            cx.propagate();
13015            return;
13016        }
13017
13018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13019
13020        let text_layout_details = &self.text_layout_details(window);
13021
13022        self.change_selections(Default::default(), window, cx, |s| {
13023            s.move_with(|map, selection| {
13024                if !selection.is_empty() {
13025                    selection.goal = SelectionGoal::None;
13026                }
13027                let (cursor, goal) = movement::up_by_rows(
13028                    map,
13029                    selection.start,
13030                    action.lines,
13031                    selection.goal,
13032                    false,
13033                    text_layout_details,
13034                );
13035                selection.collapse_to(cursor, goal);
13036            });
13037        })
13038    }
13039
13040    pub fn move_down_by_lines(
13041        &mut self,
13042        action: &MoveDownByLines,
13043        window: &mut Window,
13044        cx: &mut Context<Self>,
13045    ) {
13046        if self.take_rename(true, window, cx).is_some() {
13047            return;
13048        }
13049
13050        if self.mode.is_single_line() {
13051            cx.propagate();
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_with(|map, selection| {
13061                if !selection.is_empty() {
13062                    selection.goal = SelectionGoal::None;
13063                }
13064                let (cursor, goal) = movement::down_by_rows(
13065                    map,
13066                    selection.start,
13067                    action.lines,
13068                    selection.goal,
13069                    false,
13070                    text_layout_details,
13071                );
13072                selection.collapse_to(cursor, goal);
13073            });
13074        })
13075    }
13076
13077    pub fn select_down_by_lines(
13078        &mut self,
13079        action: &SelectDownByLines,
13080        window: &mut Window,
13081        cx: &mut Context<Self>,
13082    ) {
13083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13084        let text_layout_details = &self.text_layout_details(window);
13085        self.change_selections(Default::default(), window, cx, |s| {
13086            s.move_heads_with(|map, head, goal| {
13087                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13088            })
13089        })
13090    }
13091
13092    pub fn select_up_by_lines(
13093        &mut self,
13094        action: &SelectUpByLines,
13095        window: &mut Window,
13096        cx: &mut Context<Self>,
13097    ) {
13098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13099        let text_layout_details = &self.text_layout_details(window);
13100        self.change_selections(Default::default(), window, cx, |s| {
13101            s.move_heads_with(|map, head, goal| {
13102                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13103            })
13104        })
13105    }
13106
13107    pub fn select_page_up(
13108        &mut self,
13109        _: &SelectPageUp,
13110        window: &mut Window,
13111        cx: &mut Context<Self>,
13112    ) {
13113        let Some(row_count) = self.visible_row_count() else {
13114            return;
13115        };
13116
13117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13118
13119        let text_layout_details = &self.text_layout_details(window);
13120
13121        self.change_selections(Default::default(), window, cx, |s| {
13122            s.move_heads_with(|map, head, goal| {
13123                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13124            })
13125        })
13126    }
13127
13128    pub fn move_page_up(
13129        &mut self,
13130        action: &MovePageUp,
13131        window: &mut Window,
13132        cx: &mut Context<Self>,
13133    ) {
13134        if self.take_rename(true, window, cx).is_some() {
13135            return;
13136        }
13137
13138        if self
13139            .context_menu
13140            .borrow_mut()
13141            .as_mut()
13142            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13143            .unwrap_or(false)
13144        {
13145            return;
13146        }
13147
13148        if matches!(self.mode, EditorMode::SingleLine) {
13149            cx.propagate();
13150            return;
13151        }
13152
13153        let Some(row_count) = self.visible_row_count() else {
13154            return;
13155        };
13156
13157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13158
13159        let effects = if action.center_cursor {
13160            SelectionEffects::scroll(Autoscroll::center())
13161        } else {
13162            SelectionEffects::default()
13163        };
13164
13165        let text_layout_details = &self.text_layout_details(window);
13166
13167        self.change_selections(effects, window, cx, |s| {
13168            s.move_with(|map, selection| {
13169                if !selection.is_empty() {
13170                    selection.goal = SelectionGoal::None;
13171                }
13172                let (cursor, goal) = movement::up_by_rows(
13173                    map,
13174                    selection.end,
13175                    row_count,
13176                    selection.goal,
13177                    false,
13178                    text_layout_details,
13179                );
13180                selection.collapse_to(cursor, goal);
13181            });
13182        });
13183    }
13184
13185    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13187        let text_layout_details = &self.text_layout_details(window);
13188        self.change_selections(Default::default(), window, cx, |s| {
13189            s.move_heads_with(|map, head, goal| {
13190                movement::up(map, head, goal, false, text_layout_details)
13191            })
13192        })
13193    }
13194
13195    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13196        self.take_rename(true, window, cx);
13197
13198        if self.mode.is_single_line() {
13199            cx.propagate();
13200            return;
13201        }
13202
13203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13204
13205        let text_layout_details = &self.text_layout_details(window);
13206        let selection_count = self.selections.count();
13207        let first_selection = self.selections.first_anchor();
13208
13209        self.change_selections(Default::default(), window, cx, |s| {
13210            s.move_with(|map, selection| {
13211                if !selection.is_empty() {
13212                    selection.goal = SelectionGoal::None;
13213                }
13214                let (cursor, goal) = movement::down(
13215                    map,
13216                    selection.end,
13217                    selection.goal,
13218                    false,
13219                    text_layout_details,
13220                );
13221                selection.collapse_to(cursor, goal);
13222            });
13223        });
13224
13225        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13226        {
13227            cx.propagate();
13228        }
13229    }
13230
13231    pub fn select_page_down(
13232        &mut self,
13233        _: &SelectPageDown,
13234        window: &mut Window,
13235        cx: &mut Context<Self>,
13236    ) {
13237        let Some(row_count) = self.visible_row_count() else {
13238            return;
13239        };
13240
13241        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13242
13243        let text_layout_details = &self.text_layout_details(window);
13244
13245        self.change_selections(Default::default(), window, cx, |s| {
13246            s.move_heads_with(|map, head, goal| {
13247                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13248            })
13249        })
13250    }
13251
13252    pub fn move_page_down(
13253        &mut self,
13254        action: &MovePageDown,
13255        window: &mut Window,
13256        cx: &mut Context<Self>,
13257    ) {
13258        if self.take_rename(true, window, cx).is_some() {
13259            return;
13260        }
13261
13262        if self
13263            .context_menu
13264            .borrow_mut()
13265            .as_mut()
13266            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13267            .unwrap_or(false)
13268        {
13269            return;
13270        }
13271
13272        if matches!(self.mode, EditorMode::SingleLine) {
13273            cx.propagate();
13274            return;
13275        }
13276
13277        let Some(row_count) = self.visible_row_count() else {
13278            return;
13279        };
13280
13281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13282
13283        let effects = if action.center_cursor {
13284            SelectionEffects::scroll(Autoscroll::center())
13285        } else {
13286            SelectionEffects::default()
13287        };
13288
13289        let text_layout_details = &self.text_layout_details(window);
13290        self.change_selections(effects, window, cx, |s| {
13291            s.move_with(|map, selection| {
13292                if !selection.is_empty() {
13293                    selection.goal = SelectionGoal::None;
13294                }
13295                let (cursor, goal) = movement::down_by_rows(
13296                    map,
13297                    selection.end,
13298                    row_count,
13299                    selection.goal,
13300                    false,
13301                    text_layout_details,
13302                );
13303                selection.collapse_to(cursor, goal);
13304            });
13305        });
13306    }
13307
13308    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13309        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13310        let text_layout_details = &self.text_layout_details(window);
13311        self.change_selections(Default::default(), window, cx, |s| {
13312            s.move_heads_with(|map, head, goal| {
13313                movement::down(map, head, goal, false, text_layout_details)
13314            })
13315        });
13316    }
13317
13318    pub fn context_menu_first(
13319        &mut self,
13320        _: &ContextMenuFirst,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13325            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13326        }
13327    }
13328
13329    pub fn context_menu_prev(
13330        &mut self,
13331        _: &ContextMenuPrevious,
13332        window: &mut Window,
13333        cx: &mut Context<Self>,
13334    ) {
13335        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13336            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13337        }
13338    }
13339
13340    pub fn context_menu_next(
13341        &mut self,
13342        _: &ContextMenuNext,
13343        window: &mut Window,
13344        cx: &mut Context<Self>,
13345    ) {
13346        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13347            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13348        }
13349    }
13350
13351    pub fn context_menu_last(
13352        &mut self,
13353        _: &ContextMenuLast,
13354        window: &mut Window,
13355        cx: &mut Context<Self>,
13356    ) {
13357        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13358            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13359        }
13360    }
13361
13362    pub fn signature_help_prev(
13363        &mut self,
13364        _: &SignatureHelpPrevious,
13365        _: &mut Window,
13366        cx: &mut Context<Self>,
13367    ) {
13368        if let Some(popover) = self.signature_help_state.popover_mut() {
13369            if popover.current_signature == 0 {
13370                popover.current_signature = popover.signatures.len() - 1;
13371            } else {
13372                popover.current_signature -= 1;
13373            }
13374            cx.notify();
13375        }
13376    }
13377
13378    pub fn signature_help_next(
13379        &mut self,
13380        _: &SignatureHelpNext,
13381        _: &mut Window,
13382        cx: &mut Context<Self>,
13383    ) {
13384        if let Some(popover) = self.signature_help_state.popover_mut() {
13385            if popover.current_signature + 1 == popover.signatures.len() {
13386                popover.current_signature = 0;
13387            } else {
13388                popover.current_signature += 1;
13389            }
13390            cx.notify();
13391        }
13392    }
13393
13394    pub fn move_to_previous_word_start(
13395        &mut self,
13396        _: &MoveToPreviousWordStart,
13397        window: &mut Window,
13398        cx: &mut Context<Self>,
13399    ) {
13400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13401        self.change_selections(Default::default(), window, cx, |s| {
13402            s.move_cursors_with(|map, head, _| {
13403                (
13404                    movement::previous_word_start(map, head),
13405                    SelectionGoal::None,
13406                )
13407            });
13408        })
13409    }
13410
13411    pub fn move_to_previous_subword_start(
13412        &mut self,
13413        _: &MoveToPreviousSubwordStart,
13414        window: &mut Window,
13415        cx: &mut Context<Self>,
13416    ) {
13417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13418        self.change_selections(Default::default(), window, cx, |s| {
13419            s.move_cursors_with(|map, head, _| {
13420                (
13421                    movement::previous_subword_start(map, head),
13422                    SelectionGoal::None,
13423                )
13424            });
13425        })
13426    }
13427
13428    pub fn select_to_previous_word_start(
13429        &mut self,
13430        _: &SelectToPreviousWordStart,
13431        window: &mut Window,
13432        cx: &mut Context<Self>,
13433    ) {
13434        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13435        self.change_selections(Default::default(), window, cx, |s| {
13436            s.move_heads_with(|map, head, _| {
13437                (
13438                    movement::previous_word_start(map, head),
13439                    SelectionGoal::None,
13440                )
13441            });
13442        })
13443    }
13444
13445    pub fn select_to_previous_subword_start(
13446        &mut self,
13447        _: &SelectToPreviousSubwordStart,
13448        window: &mut Window,
13449        cx: &mut Context<Self>,
13450    ) {
13451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13452        self.change_selections(Default::default(), window, cx, |s| {
13453            s.move_heads_with(|map, head, _| {
13454                (
13455                    movement::previous_subword_start(map, head),
13456                    SelectionGoal::None,
13457                )
13458            });
13459        })
13460    }
13461
13462    pub fn delete_to_previous_word_start(
13463        &mut self,
13464        action: &DeleteToPreviousWordStart,
13465        window: &mut Window,
13466        cx: &mut Context<Self>,
13467    ) {
13468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13469        self.transact(window, cx, |this, window, cx| {
13470            this.select_autoclose_pair(window, cx);
13471            this.change_selections(Default::default(), window, cx, |s| {
13472                s.move_with(|map, selection| {
13473                    if selection.is_empty() {
13474                        let mut cursor = if action.ignore_newlines {
13475                            movement::previous_word_start(map, selection.head())
13476                        } else {
13477                            movement::previous_word_start_or_newline(map, selection.head())
13478                        };
13479                        cursor = movement::adjust_greedy_deletion(
13480                            map,
13481                            selection.head(),
13482                            cursor,
13483                            action.ignore_brackets,
13484                        );
13485                        selection.set_head(cursor, SelectionGoal::None);
13486                    }
13487                });
13488            });
13489            this.insert("", window, cx);
13490        });
13491    }
13492
13493    pub fn delete_to_previous_subword_start(
13494        &mut self,
13495        _: &DeleteToPreviousSubwordStart,
13496        window: &mut Window,
13497        cx: &mut Context<Self>,
13498    ) {
13499        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13500        self.transact(window, cx, |this, window, cx| {
13501            this.select_autoclose_pair(window, cx);
13502            this.change_selections(Default::default(), window, cx, |s| {
13503                s.move_with(|map, selection| {
13504                    if selection.is_empty() {
13505                        let mut cursor = movement::previous_subword_start(map, selection.head());
13506                        cursor =
13507                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13508                        selection.set_head(cursor, SelectionGoal::None);
13509                    }
13510                });
13511            });
13512            this.insert("", window, cx);
13513        });
13514    }
13515
13516    pub fn move_to_next_word_end(
13517        &mut self,
13518        _: &MoveToNextWordEnd,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13523        self.change_selections(Default::default(), window, cx, |s| {
13524            s.move_cursors_with(|map, head, _| {
13525                (movement::next_word_end(map, head), SelectionGoal::None)
13526            });
13527        })
13528    }
13529
13530    pub fn move_to_next_subword_end(
13531        &mut self,
13532        _: &MoveToNextSubwordEnd,
13533        window: &mut Window,
13534        cx: &mut Context<Self>,
13535    ) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13537        self.change_selections(Default::default(), window, cx, |s| {
13538            s.move_cursors_with(|map, head, _| {
13539                (movement::next_subword_end(map, head), SelectionGoal::None)
13540            });
13541        })
13542    }
13543
13544    pub fn select_to_next_word_end(
13545        &mut self,
13546        _: &SelectToNextWordEnd,
13547        window: &mut Window,
13548        cx: &mut Context<Self>,
13549    ) {
13550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13551        self.change_selections(Default::default(), window, cx, |s| {
13552            s.move_heads_with(|map, head, _| {
13553                (movement::next_word_end(map, head), SelectionGoal::None)
13554            });
13555        })
13556    }
13557
13558    pub fn select_to_next_subword_end(
13559        &mut self,
13560        _: &SelectToNextSubwordEnd,
13561        window: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13565        self.change_selections(Default::default(), window, cx, |s| {
13566            s.move_heads_with(|map, head, _| {
13567                (movement::next_subword_end(map, head), SelectionGoal::None)
13568            });
13569        })
13570    }
13571
13572    pub fn delete_to_next_word_end(
13573        &mut self,
13574        action: &DeleteToNextWordEnd,
13575        window: &mut Window,
13576        cx: &mut Context<Self>,
13577    ) {
13578        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13579        self.transact(window, cx, |this, window, cx| {
13580            this.change_selections(Default::default(), window, cx, |s| {
13581                s.move_with(|map, selection| {
13582                    if selection.is_empty() {
13583                        let mut cursor = if action.ignore_newlines {
13584                            movement::next_word_end(map, selection.head())
13585                        } else {
13586                            movement::next_word_end_or_newline(map, selection.head())
13587                        };
13588                        cursor = movement::adjust_greedy_deletion(
13589                            map,
13590                            selection.head(),
13591                            cursor,
13592                            action.ignore_brackets,
13593                        );
13594                        selection.set_head(cursor, SelectionGoal::None);
13595                    }
13596                });
13597            });
13598            this.insert("", window, cx);
13599        });
13600    }
13601
13602    pub fn delete_to_next_subword_end(
13603        &mut self,
13604        _: &DeleteToNextSubwordEnd,
13605        window: &mut Window,
13606        cx: &mut Context<Self>,
13607    ) {
13608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13609        self.transact(window, cx, |this, window, cx| {
13610            this.change_selections(Default::default(), window, cx, |s| {
13611                s.move_with(|map, selection| {
13612                    if selection.is_empty() {
13613                        let mut cursor = movement::next_subword_end(map, selection.head());
13614                        cursor =
13615                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13616                        selection.set_head(cursor, SelectionGoal::None);
13617                    }
13618                });
13619            });
13620            this.insert("", window, cx);
13621        });
13622    }
13623
13624    pub fn move_to_beginning_of_line(
13625        &mut self,
13626        action: &MoveToBeginningOfLine,
13627        window: &mut Window,
13628        cx: &mut Context<Self>,
13629    ) {
13630        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13631        self.change_selections(Default::default(), window, cx, |s| {
13632            s.move_cursors_with(|map, head, _| {
13633                (
13634                    movement::indented_line_beginning(
13635                        map,
13636                        head,
13637                        action.stop_at_soft_wraps,
13638                        action.stop_at_indent,
13639                    ),
13640                    SelectionGoal::None,
13641                )
13642            });
13643        })
13644    }
13645
13646    pub fn select_to_beginning_of_line(
13647        &mut self,
13648        action: &SelectToBeginningOfLine,
13649        window: &mut Window,
13650        cx: &mut Context<Self>,
13651    ) {
13652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13653        self.change_selections(Default::default(), window, cx, |s| {
13654            s.move_heads_with(|map, head, _| {
13655                (
13656                    movement::indented_line_beginning(
13657                        map,
13658                        head,
13659                        action.stop_at_soft_wraps,
13660                        action.stop_at_indent,
13661                    ),
13662                    SelectionGoal::None,
13663                )
13664            });
13665        });
13666    }
13667
13668    pub fn delete_to_beginning_of_line(
13669        &mut self,
13670        action: &DeleteToBeginningOfLine,
13671        window: &mut Window,
13672        cx: &mut Context<Self>,
13673    ) {
13674        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13675        self.transact(window, cx, |this, window, cx| {
13676            this.change_selections(Default::default(), window, cx, |s| {
13677                s.move_with(|_, selection| {
13678                    selection.reversed = true;
13679                });
13680            });
13681
13682            this.select_to_beginning_of_line(
13683                &SelectToBeginningOfLine {
13684                    stop_at_soft_wraps: false,
13685                    stop_at_indent: action.stop_at_indent,
13686                },
13687                window,
13688                cx,
13689            );
13690            this.backspace(&Backspace, window, cx);
13691        });
13692    }
13693
13694    pub fn move_to_end_of_line(
13695        &mut self,
13696        action: &MoveToEndOfLine,
13697        window: &mut Window,
13698        cx: &mut Context<Self>,
13699    ) {
13700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13701        self.change_selections(Default::default(), window, cx, |s| {
13702            s.move_cursors_with(|map, head, _| {
13703                (
13704                    movement::line_end(map, head, action.stop_at_soft_wraps),
13705                    SelectionGoal::None,
13706                )
13707            });
13708        })
13709    }
13710
13711    pub fn select_to_end_of_line(
13712        &mut self,
13713        action: &SelectToEndOfLine,
13714        window: &mut Window,
13715        cx: &mut Context<Self>,
13716    ) {
13717        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13718        self.change_selections(Default::default(), window, cx, |s| {
13719            s.move_heads_with(|map, head, _| {
13720                (
13721                    movement::line_end(map, head, action.stop_at_soft_wraps),
13722                    SelectionGoal::None,
13723                )
13724            });
13725        })
13726    }
13727
13728    pub fn delete_to_end_of_line(
13729        &mut self,
13730        _: &DeleteToEndOfLine,
13731        window: &mut Window,
13732        cx: &mut Context<Self>,
13733    ) {
13734        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13735        self.transact(window, cx, |this, window, cx| {
13736            this.select_to_end_of_line(
13737                &SelectToEndOfLine {
13738                    stop_at_soft_wraps: false,
13739                },
13740                window,
13741                cx,
13742            );
13743            this.delete(&Delete, window, cx);
13744        });
13745    }
13746
13747    pub fn cut_to_end_of_line(
13748        &mut self,
13749        action: &CutToEndOfLine,
13750        window: &mut Window,
13751        cx: &mut Context<Self>,
13752    ) {
13753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13754        self.transact(window, cx, |this, window, cx| {
13755            this.select_to_end_of_line(
13756                &SelectToEndOfLine {
13757                    stop_at_soft_wraps: false,
13758                },
13759                window,
13760                cx,
13761            );
13762            if !action.stop_at_newlines {
13763                this.change_selections(Default::default(), window, cx, |s| {
13764                    s.move_with(|_, sel| {
13765                        if sel.is_empty() {
13766                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13767                        }
13768                    });
13769                });
13770            }
13771            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13772            let item = this.cut_common(false, window, cx);
13773            cx.write_to_clipboard(item);
13774        });
13775    }
13776
13777    pub fn move_to_start_of_paragraph(
13778        &mut self,
13779        _: &MoveToStartOfParagraph,
13780        window: &mut Window,
13781        cx: &mut Context<Self>,
13782    ) {
13783        if matches!(self.mode, EditorMode::SingleLine) {
13784            cx.propagate();
13785            return;
13786        }
13787        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13788        self.change_selections(Default::default(), window, cx, |s| {
13789            s.move_with(|map, selection| {
13790                selection.collapse_to(
13791                    movement::start_of_paragraph(map, selection.head(), 1),
13792                    SelectionGoal::None,
13793                )
13794            });
13795        })
13796    }
13797
13798    pub fn move_to_end_of_paragraph(
13799        &mut self,
13800        _: &MoveToEndOfParagraph,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        if matches!(self.mode, EditorMode::SingleLine) {
13805            cx.propagate();
13806            return;
13807        }
13808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13809        self.change_selections(Default::default(), window, cx, |s| {
13810            s.move_with(|map, selection| {
13811                selection.collapse_to(
13812                    movement::end_of_paragraph(map, selection.head(), 1),
13813                    SelectionGoal::None,
13814                )
13815            });
13816        })
13817    }
13818
13819    pub fn select_to_start_of_paragraph(
13820        &mut self,
13821        _: &SelectToStartOfParagraph,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) {
13825        if matches!(self.mode, EditorMode::SingleLine) {
13826            cx.propagate();
13827            return;
13828        }
13829        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13830        self.change_selections(Default::default(), window, cx, |s| {
13831            s.move_heads_with(|map, head, _| {
13832                (
13833                    movement::start_of_paragraph(map, head, 1),
13834                    SelectionGoal::None,
13835                )
13836            });
13837        })
13838    }
13839
13840    pub fn select_to_end_of_paragraph(
13841        &mut self,
13842        _: &SelectToEndOfParagraph,
13843        window: &mut Window,
13844        cx: &mut Context<Self>,
13845    ) {
13846        if matches!(self.mode, EditorMode::SingleLine) {
13847            cx.propagate();
13848            return;
13849        }
13850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13851        self.change_selections(Default::default(), window, cx, |s| {
13852            s.move_heads_with(|map, head, _| {
13853                (
13854                    movement::end_of_paragraph(map, head, 1),
13855                    SelectionGoal::None,
13856                )
13857            });
13858        })
13859    }
13860
13861    pub fn move_to_start_of_excerpt(
13862        &mut self,
13863        _: &MoveToStartOfExcerpt,
13864        window: &mut Window,
13865        cx: &mut Context<Self>,
13866    ) {
13867        if matches!(self.mode, EditorMode::SingleLine) {
13868            cx.propagate();
13869            return;
13870        }
13871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13872        self.change_selections(Default::default(), window, cx, |s| {
13873            s.move_with(|map, selection| {
13874                selection.collapse_to(
13875                    movement::start_of_excerpt(
13876                        map,
13877                        selection.head(),
13878                        workspace::searchable::Direction::Prev,
13879                    ),
13880                    SelectionGoal::None,
13881                )
13882            });
13883        })
13884    }
13885
13886    pub fn move_to_start_of_next_excerpt(
13887        &mut self,
13888        _: &MoveToStartOfNextExcerpt,
13889        window: &mut Window,
13890        cx: &mut Context<Self>,
13891    ) {
13892        if matches!(self.mode, EditorMode::SingleLine) {
13893            cx.propagate();
13894            return;
13895        }
13896
13897        self.change_selections(Default::default(), window, cx, |s| {
13898            s.move_with(|map, selection| {
13899                selection.collapse_to(
13900                    movement::start_of_excerpt(
13901                        map,
13902                        selection.head(),
13903                        workspace::searchable::Direction::Next,
13904                    ),
13905                    SelectionGoal::None,
13906                )
13907            });
13908        })
13909    }
13910
13911    pub fn move_to_end_of_excerpt(
13912        &mut self,
13913        _: &MoveToEndOfExcerpt,
13914        window: &mut Window,
13915        cx: &mut Context<Self>,
13916    ) {
13917        if matches!(self.mode, EditorMode::SingleLine) {
13918            cx.propagate();
13919            return;
13920        }
13921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13922        self.change_selections(Default::default(), window, cx, |s| {
13923            s.move_with(|map, selection| {
13924                selection.collapse_to(
13925                    movement::end_of_excerpt(
13926                        map,
13927                        selection.head(),
13928                        workspace::searchable::Direction::Next,
13929                    ),
13930                    SelectionGoal::None,
13931                )
13932            });
13933        })
13934    }
13935
13936    pub fn move_to_end_of_previous_excerpt(
13937        &mut self,
13938        _: &MoveToEndOfPreviousExcerpt,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) {
13942        if matches!(self.mode, EditorMode::SingleLine) {
13943            cx.propagate();
13944            return;
13945        }
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_with(|map, selection| {
13949                selection.collapse_to(
13950                    movement::end_of_excerpt(
13951                        map,
13952                        selection.head(),
13953                        workspace::searchable::Direction::Prev,
13954                    ),
13955                    SelectionGoal::None,
13956                )
13957            });
13958        })
13959    }
13960
13961    pub fn select_to_start_of_excerpt(
13962        &mut self,
13963        _: &SelectToStartOfExcerpt,
13964        window: &mut Window,
13965        cx: &mut Context<Self>,
13966    ) {
13967        if matches!(self.mode, EditorMode::SingleLine) {
13968            cx.propagate();
13969            return;
13970        }
13971        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13972        self.change_selections(Default::default(), window, cx, |s| {
13973            s.move_heads_with(|map, head, _| {
13974                (
13975                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13976                    SelectionGoal::None,
13977                )
13978            });
13979        })
13980    }
13981
13982    pub fn select_to_start_of_next_excerpt(
13983        &mut self,
13984        _: &SelectToStartOfNextExcerpt,
13985        window: &mut Window,
13986        cx: &mut Context<Self>,
13987    ) {
13988        if matches!(self.mode, EditorMode::SingleLine) {
13989            cx.propagate();
13990            return;
13991        }
13992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13993        self.change_selections(Default::default(), window, cx, |s| {
13994            s.move_heads_with(|map, head, _| {
13995                (
13996                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13997                    SelectionGoal::None,
13998                )
13999            });
14000        })
14001    }
14002
14003    pub fn select_to_end_of_excerpt(
14004        &mut self,
14005        _: &SelectToEndOfExcerpt,
14006        window: &mut Window,
14007        cx: &mut Context<Self>,
14008    ) {
14009        if matches!(self.mode, EditorMode::SingleLine) {
14010            cx.propagate();
14011            return;
14012        }
14013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14014        self.change_selections(Default::default(), window, cx, |s| {
14015            s.move_heads_with(|map, head, _| {
14016                (
14017                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14018                    SelectionGoal::None,
14019                )
14020            });
14021        })
14022    }
14023
14024    pub fn select_to_end_of_previous_excerpt(
14025        &mut self,
14026        _: &SelectToEndOfPreviousExcerpt,
14027        window: &mut Window,
14028        cx: &mut Context<Self>,
14029    ) {
14030        if matches!(self.mode, EditorMode::SingleLine) {
14031            cx.propagate();
14032            return;
14033        }
14034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14035        self.change_selections(Default::default(), window, cx, |s| {
14036            s.move_heads_with(|map, head, _| {
14037                (
14038                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14039                    SelectionGoal::None,
14040                )
14041            });
14042        })
14043    }
14044
14045    pub fn move_to_beginning(
14046        &mut self,
14047        _: &MoveToBeginning,
14048        window: &mut Window,
14049        cx: &mut Context<Self>,
14050    ) {
14051        if matches!(self.mode, EditorMode::SingleLine) {
14052            cx.propagate();
14053            return;
14054        }
14055        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14056        self.change_selections(Default::default(), window, cx, |s| {
14057            s.select_ranges(vec![0..0]);
14058        });
14059    }
14060
14061    pub fn select_to_beginning(
14062        &mut self,
14063        _: &SelectToBeginning,
14064        window: &mut Window,
14065        cx: &mut Context<Self>,
14066    ) {
14067        let mut selection = self.selections.last::<Point>(cx);
14068        selection.set_head(Point::zero(), SelectionGoal::None);
14069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14070        self.change_selections(Default::default(), window, cx, |s| {
14071            s.select(vec![selection]);
14072        });
14073    }
14074
14075    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14076        if matches!(self.mode, EditorMode::SingleLine) {
14077            cx.propagate();
14078            return;
14079        }
14080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14081        let cursor = self.buffer.read(cx).read(cx).len();
14082        self.change_selections(Default::default(), window, cx, |s| {
14083            s.select_ranges(vec![cursor..cursor])
14084        });
14085    }
14086
14087    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14088        self.nav_history = nav_history;
14089    }
14090
14091    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14092        self.nav_history.as_ref()
14093    }
14094
14095    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14096        self.push_to_nav_history(
14097            self.selections.newest_anchor().head(),
14098            None,
14099            false,
14100            true,
14101            cx,
14102        );
14103    }
14104
14105    fn push_to_nav_history(
14106        &mut self,
14107        cursor_anchor: Anchor,
14108        new_position: Option<Point>,
14109        is_deactivate: bool,
14110        always: bool,
14111        cx: &mut Context<Self>,
14112    ) {
14113        if let Some(nav_history) = self.nav_history.as_mut() {
14114            let buffer = self.buffer.read(cx).read(cx);
14115            let cursor_position = cursor_anchor.to_point(&buffer);
14116            let scroll_state = self.scroll_manager.anchor();
14117            let scroll_top_row = scroll_state.top_row(&buffer);
14118            drop(buffer);
14119
14120            if let Some(new_position) = new_position {
14121                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14122                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14123                    return;
14124                }
14125            }
14126
14127            nav_history.push(
14128                Some(NavigationData {
14129                    cursor_anchor,
14130                    cursor_position,
14131                    scroll_anchor: scroll_state,
14132                    scroll_top_row,
14133                }),
14134                cx,
14135            );
14136            cx.emit(EditorEvent::PushedToNavHistory {
14137                anchor: cursor_anchor,
14138                is_deactivate,
14139            })
14140        }
14141    }
14142
14143    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14144        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14145        let buffer = self.buffer.read(cx).snapshot(cx);
14146        let mut selection = self.selections.first::<usize>(cx);
14147        selection.set_head(buffer.len(), SelectionGoal::None);
14148        self.change_selections(Default::default(), window, cx, |s| {
14149            s.select(vec![selection]);
14150        });
14151    }
14152
14153    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14155        let end = self.buffer.read(cx).read(cx).len();
14156        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14157            s.select_ranges(vec![0..end]);
14158        });
14159    }
14160
14161    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14163        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14164        let mut selections = self.selections.all::<Point>(cx);
14165        let max_point = display_map.buffer_snapshot().max_point();
14166        for selection in &mut selections {
14167            let rows = selection.spanned_rows(true, &display_map);
14168            selection.start = Point::new(rows.start.0, 0);
14169            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14170            selection.reversed = false;
14171        }
14172        self.change_selections(Default::default(), window, cx, |s| {
14173            s.select(selections);
14174        });
14175    }
14176
14177    pub fn split_selection_into_lines(
14178        &mut self,
14179        action: &SplitSelectionIntoLines,
14180        window: &mut Window,
14181        cx: &mut Context<Self>,
14182    ) {
14183        let selections = self
14184            .selections
14185            .all::<Point>(cx)
14186            .into_iter()
14187            .map(|selection| selection.start..selection.end)
14188            .collect::<Vec<_>>();
14189        self.unfold_ranges(&selections, true, true, cx);
14190
14191        let mut new_selection_ranges = Vec::new();
14192        {
14193            let buffer = self.buffer.read(cx).read(cx);
14194            for selection in selections {
14195                for row in selection.start.row..selection.end.row {
14196                    let line_start = Point::new(row, 0);
14197                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14198
14199                    if action.keep_selections {
14200                        // Keep the selection range for each line
14201                        let selection_start = if row == selection.start.row {
14202                            selection.start
14203                        } else {
14204                            line_start
14205                        };
14206                        new_selection_ranges.push(selection_start..line_end);
14207                    } else {
14208                        // Collapse to cursor at end of line
14209                        new_selection_ranges.push(line_end..line_end);
14210                    }
14211                }
14212
14213                let is_multiline_selection = selection.start.row != selection.end.row;
14214                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14215                // so this action feels more ergonomic when paired with other selection operations
14216                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14217                if !should_skip_last {
14218                    if action.keep_selections {
14219                        if is_multiline_selection {
14220                            let line_start = Point::new(selection.end.row, 0);
14221                            new_selection_ranges.push(line_start..selection.end);
14222                        } else {
14223                            new_selection_ranges.push(selection.start..selection.end);
14224                        }
14225                    } else {
14226                        new_selection_ranges.push(selection.end..selection.end);
14227                    }
14228                }
14229            }
14230        }
14231        self.change_selections(Default::default(), window, cx, |s| {
14232            s.select_ranges(new_selection_ranges);
14233        });
14234    }
14235
14236    pub fn add_selection_above(
14237        &mut self,
14238        _: &AddSelectionAbove,
14239        window: &mut Window,
14240        cx: &mut Context<Self>,
14241    ) {
14242        self.add_selection(true, window, cx);
14243    }
14244
14245    pub fn add_selection_below(
14246        &mut self,
14247        _: &AddSelectionBelow,
14248        window: &mut Window,
14249        cx: &mut Context<Self>,
14250    ) {
14251        self.add_selection(false, window, cx);
14252    }
14253
14254    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14256
14257        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14258        let all_selections = self.selections.all::<Point>(cx);
14259        let text_layout_details = self.text_layout_details(window);
14260
14261        let (mut columnar_selections, new_selections_to_columnarize) = {
14262            if let Some(state) = self.add_selections_state.as_ref() {
14263                let columnar_selection_ids: HashSet<_> = state
14264                    .groups
14265                    .iter()
14266                    .flat_map(|group| group.stack.iter())
14267                    .copied()
14268                    .collect();
14269
14270                all_selections
14271                    .into_iter()
14272                    .partition(|s| columnar_selection_ids.contains(&s.id))
14273            } else {
14274                (Vec::new(), all_selections)
14275            }
14276        };
14277
14278        let mut state = self
14279            .add_selections_state
14280            .take()
14281            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14282
14283        for selection in new_selections_to_columnarize {
14284            let range = selection.display_range(&display_map).sorted();
14285            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14286            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14287            let positions = start_x.min(end_x)..start_x.max(end_x);
14288            let mut stack = Vec::new();
14289            for row in range.start.row().0..=range.end.row().0 {
14290                if let Some(selection) = self.selections.build_columnar_selection(
14291                    &display_map,
14292                    DisplayRow(row),
14293                    &positions,
14294                    selection.reversed,
14295                    &text_layout_details,
14296                ) {
14297                    stack.push(selection.id);
14298                    columnar_selections.push(selection);
14299                }
14300            }
14301            if !stack.is_empty() {
14302                if above {
14303                    stack.reverse();
14304                }
14305                state.groups.push(AddSelectionsGroup { above, stack });
14306            }
14307        }
14308
14309        let mut final_selections = Vec::new();
14310        let end_row = if above {
14311            DisplayRow(0)
14312        } else {
14313            display_map.max_point().row()
14314        };
14315
14316        let mut last_added_item_per_group = HashMap::default();
14317        for group in state.groups.iter_mut() {
14318            if let Some(last_id) = group.stack.last() {
14319                last_added_item_per_group.insert(*last_id, group);
14320            }
14321        }
14322
14323        for selection in columnar_selections {
14324            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14325                if above == group.above {
14326                    let range = selection.display_range(&display_map).sorted();
14327                    debug_assert_eq!(range.start.row(), range.end.row());
14328                    let mut row = range.start.row();
14329                    let positions =
14330                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14331                            Pixels::from(start)..Pixels::from(end)
14332                        } else {
14333                            let start_x =
14334                                display_map.x_for_display_point(range.start, &text_layout_details);
14335                            let end_x =
14336                                display_map.x_for_display_point(range.end, &text_layout_details);
14337                            start_x.min(end_x)..start_x.max(end_x)
14338                        };
14339
14340                    let mut maybe_new_selection = None;
14341                    while row != end_row {
14342                        if above {
14343                            row.0 -= 1;
14344                        } else {
14345                            row.0 += 1;
14346                        }
14347                        if let Some(new_selection) = self.selections.build_columnar_selection(
14348                            &display_map,
14349                            row,
14350                            &positions,
14351                            selection.reversed,
14352                            &text_layout_details,
14353                        ) {
14354                            maybe_new_selection = Some(new_selection);
14355                            break;
14356                        }
14357                    }
14358
14359                    if let Some(new_selection) = maybe_new_selection {
14360                        group.stack.push(new_selection.id);
14361                        if above {
14362                            final_selections.push(new_selection);
14363                            final_selections.push(selection);
14364                        } else {
14365                            final_selections.push(selection);
14366                            final_selections.push(new_selection);
14367                        }
14368                    } else {
14369                        final_selections.push(selection);
14370                    }
14371                } else {
14372                    group.stack.pop();
14373                }
14374            } else {
14375                final_selections.push(selection);
14376            }
14377        }
14378
14379        self.change_selections(Default::default(), window, cx, |s| {
14380            s.select(final_selections);
14381        });
14382
14383        let final_selection_ids: HashSet<_> = self
14384            .selections
14385            .all::<Point>(cx)
14386            .iter()
14387            .map(|s| s.id)
14388            .collect();
14389        state.groups.retain_mut(|group| {
14390            // selections might get merged above so we remove invalid items from stacks
14391            group.stack.retain(|id| final_selection_ids.contains(id));
14392
14393            // single selection in stack can be treated as initial state
14394            group.stack.len() > 1
14395        });
14396
14397        if !state.groups.is_empty() {
14398            self.add_selections_state = Some(state);
14399        }
14400    }
14401
14402    fn select_match_ranges(
14403        &mut self,
14404        range: Range<usize>,
14405        reversed: bool,
14406        replace_newest: bool,
14407        auto_scroll: Option<Autoscroll>,
14408        window: &mut Window,
14409        cx: &mut Context<Editor>,
14410    ) {
14411        self.unfold_ranges(
14412            std::slice::from_ref(&range),
14413            false,
14414            auto_scroll.is_some(),
14415            cx,
14416        );
14417        let effects = if let Some(scroll) = auto_scroll {
14418            SelectionEffects::scroll(scroll)
14419        } else {
14420            SelectionEffects::no_scroll()
14421        };
14422        self.change_selections(effects, window, cx, |s| {
14423            if replace_newest {
14424                s.delete(s.newest_anchor().id);
14425            }
14426            if reversed {
14427                s.insert_range(range.end..range.start);
14428            } else {
14429                s.insert_range(range);
14430            }
14431        });
14432    }
14433
14434    pub fn select_next_match_internal(
14435        &mut self,
14436        display_map: &DisplaySnapshot,
14437        replace_newest: bool,
14438        autoscroll: Option<Autoscroll>,
14439        window: &mut Window,
14440        cx: &mut Context<Self>,
14441    ) -> Result<()> {
14442        let buffer = display_map.buffer_snapshot();
14443        let mut selections = self.selections.all::<usize>(cx);
14444        if let Some(mut select_next_state) = self.select_next_state.take() {
14445            let query = &select_next_state.query;
14446            if !select_next_state.done {
14447                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14448                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14449                let mut next_selected_range = None;
14450
14451                // Collect and sort selection ranges for efficient overlap checking
14452                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14453                selection_ranges.sort_by_key(|r| r.start);
14454
14455                let bytes_after_last_selection =
14456                    buffer.bytes_in_range(last_selection.end..buffer.len());
14457                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14458                let query_matches = query
14459                    .stream_find_iter(bytes_after_last_selection)
14460                    .map(|result| (last_selection.end, result))
14461                    .chain(
14462                        query
14463                            .stream_find_iter(bytes_before_first_selection)
14464                            .map(|result| (0, result)),
14465                    );
14466
14467                for (start_offset, query_match) in query_matches {
14468                    let query_match = query_match.unwrap(); // can only fail due to I/O
14469                    let offset_range =
14470                        start_offset + query_match.start()..start_offset + query_match.end();
14471
14472                    if !select_next_state.wordwise
14473                        || (!buffer.is_inside_word(offset_range.start, None)
14474                            && !buffer.is_inside_word(offset_range.end, None))
14475                    {
14476                        // Use binary search to check for overlap (O(log n))
14477                        let overlaps = selection_ranges
14478                            .binary_search_by(|range| {
14479                                if range.end <= offset_range.start {
14480                                    std::cmp::Ordering::Less
14481                                } else if range.start >= offset_range.end {
14482                                    std::cmp::Ordering::Greater
14483                                } else {
14484                                    std::cmp::Ordering::Equal
14485                                }
14486                            })
14487                            .is_ok();
14488
14489                        if !overlaps {
14490                            next_selected_range = Some(offset_range);
14491                            break;
14492                        }
14493                    }
14494                }
14495
14496                if let Some(next_selected_range) = next_selected_range {
14497                    self.select_match_ranges(
14498                        next_selected_range,
14499                        last_selection.reversed,
14500                        replace_newest,
14501                        autoscroll,
14502                        window,
14503                        cx,
14504                    );
14505                } else {
14506                    select_next_state.done = true;
14507                }
14508            }
14509
14510            self.select_next_state = Some(select_next_state);
14511        } else {
14512            let mut only_carets = true;
14513            let mut same_text_selected = true;
14514            let mut selected_text = None;
14515
14516            let mut selections_iter = selections.iter().peekable();
14517            while let Some(selection) = selections_iter.next() {
14518                if selection.start != selection.end {
14519                    only_carets = false;
14520                }
14521
14522                if same_text_selected {
14523                    if selected_text.is_none() {
14524                        selected_text =
14525                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14526                    }
14527
14528                    if let Some(next_selection) = selections_iter.peek() {
14529                        if next_selection.range().len() == selection.range().len() {
14530                            let next_selected_text = buffer
14531                                .text_for_range(next_selection.range())
14532                                .collect::<String>();
14533                            if Some(next_selected_text) != selected_text {
14534                                same_text_selected = false;
14535                                selected_text = None;
14536                            }
14537                        } else {
14538                            same_text_selected = false;
14539                            selected_text = None;
14540                        }
14541                    }
14542                }
14543            }
14544
14545            if only_carets {
14546                for selection in &mut selections {
14547                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14548                    selection.start = word_range.start;
14549                    selection.end = word_range.end;
14550                    selection.goal = SelectionGoal::None;
14551                    selection.reversed = false;
14552                    self.select_match_ranges(
14553                        selection.start..selection.end,
14554                        selection.reversed,
14555                        replace_newest,
14556                        autoscroll,
14557                        window,
14558                        cx,
14559                    );
14560                }
14561
14562                if selections.len() == 1 {
14563                    let selection = selections
14564                        .last()
14565                        .expect("ensured that there's only one selection");
14566                    let query = buffer
14567                        .text_for_range(selection.start..selection.end)
14568                        .collect::<String>();
14569                    let is_empty = query.is_empty();
14570                    let select_state = SelectNextState {
14571                        query: AhoCorasick::new(&[query])?,
14572                        wordwise: true,
14573                        done: is_empty,
14574                    };
14575                    self.select_next_state = Some(select_state);
14576                } else {
14577                    self.select_next_state = None;
14578                }
14579            } else if let Some(selected_text) = selected_text {
14580                self.select_next_state = Some(SelectNextState {
14581                    query: AhoCorasick::new(&[selected_text])?,
14582                    wordwise: false,
14583                    done: false,
14584                });
14585                self.select_next_match_internal(
14586                    display_map,
14587                    replace_newest,
14588                    autoscroll,
14589                    window,
14590                    cx,
14591                )?;
14592            }
14593        }
14594        Ok(())
14595    }
14596
14597    pub fn select_all_matches(
14598        &mut self,
14599        _action: &SelectAllMatches,
14600        window: &mut Window,
14601        cx: &mut Context<Self>,
14602    ) -> Result<()> {
14603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14604
14605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14606
14607        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14608        let Some(select_next_state) = self.select_next_state.as_mut() else {
14609            return Ok(());
14610        };
14611        if select_next_state.done {
14612            return Ok(());
14613        }
14614
14615        let mut new_selections = Vec::new();
14616
14617        let reversed = self.selections.oldest::<usize>(cx).reversed;
14618        let buffer = display_map.buffer_snapshot();
14619        let query_matches = select_next_state
14620            .query
14621            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14622
14623        for query_match in query_matches.into_iter() {
14624            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14625            let offset_range = if reversed {
14626                query_match.end()..query_match.start()
14627            } else {
14628                query_match.start()..query_match.end()
14629            };
14630
14631            if !select_next_state.wordwise
14632                || (!buffer.is_inside_word(offset_range.start, None)
14633                    && !buffer.is_inside_word(offset_range.end, None))
14634            {
14635                new_selections.push(offset_range.start..offset_range.end);
14636            }
14637        }
14638
14639        select_next_state.done = true;
14640
14641        if new_selections.is_empty() {
14642            log::error!("bug: new_selections is empty in select_all_matches");
14643            return Ok(());
14644        }
14645
14646        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14647        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14648            selections.select_ranges(new_selections)
14649        });
14650
14651        Ok(())
14652    }
14653
14654    pub fn select_next(
14655        &mut self,
14656        action: &SelectNext,
14657        window: &mut Window,
14658        cx: &mut Context<Self>,
14659    ) -> Result<()> {
14660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14661        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14662        self.select_next_match_internal(
14663            &display_map,
14664            action.replace_newest,
14665            Some(Autoscroll::newest()),
14666            window,
14667            cx,
14668        )?;
14669        Ok(())
14670    }
14671
14672    pub fn select_previous(
14673        &mut self,
14674        action: &SelectPrevious,
14675        window: &mut Window,
14676        cx: &mut Context<Self>,
14677    ) -> Result<()> {
14678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14680        let buffer = display_map.buffer_snapshot();
14681        let mut selections = self.selections.all::<usize>(cx);
14682        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14683            let query = &select_prev_state.query;
14684            if !select_prev_state.done {
14685                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14686                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14687                let mut next_selected_range = None;
14688                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14689                let bytes_before_last_selection =
14690                    buffer.reversed_bytes_in_range(0..last_selection.start);
14691                let bytes_after_first_selection =
14692                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14693                let query_matches = query
14694                    .stream_find_iter(bytes_before_last_selection)
14695                    .map(|result| (last_selection.start, result))
14696                    .chain(
14697                        query
14698                            .stream_find_iter(bytes_after_first_selection)
14699                            .map(|result| (buffer.len(), result)),
14700                    );
14701                for (end_offset, query_match) in query_matches {
14702                    let query_match = query_match.unwrap(); // can only fail due to I/O
14703                    let offset_range =
14704                        end_offset - query_match.end()..end_offset - query_match.start();
14705
14706                    if !select_prev_state.wordwise
14707                        || (!buffer.is_inside_word(offset_range.start, None)
14708                            && !buffer.is_inside_word(offset_range.end, None))
14709                    {
14710                        next_selected_range = Some(offset_range);
14711                        break;
14712                    }
14713                }
14714
14715                if let Some(next_selected_range) = next_selected_range {
14716                    self.select_match_ranges(
14717                        next_selected_range,
14718                        last_selection.reversed,
14719                        action.replace_newest,
14720                        Some(Autoscroll::newest()),
14721                        window,
14722                        cx,
14723                    );
14724                } else {
14725                    select_prev_state.done = true;
14726                }
14727            }
14728
14729            self.select_prev_state = Some(select_prev_state);
14730        } else {
14731            let mut only_carets = true;
14732            let mut same_text_selected = true;
14733            let mut selected_text = None;
14734
14735            let mut selections_iter = selections.iter().peekable();
14736            while let Some(selection) = selections_iter.next() {
14737                if selection.start != selection.end {
14738                    only_carets = false;
14739                }
14740
14741                if same_text_selected {
14742                    if selected_text.is_none() {
14743                        selected_text =
14744                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14745                    }
14746
14747                    if let Some(next_selection) = selections_iter.peek() {
14748                        if next_selection.range().len() == selection.range().len() {
14749                            let next_selected_text = buffer
14750                                .text_for_range(next_selection.range())
14751                                .collect::<String>();
14752                            if Some(next_selected_text) != selected_text {
14753                                same_text_selected = false;
14754                                selected_text = None;
14755                            }
14756                        } else {
14757                            same_text_selected = false;
14758                            selected_text = None;
14759                        }
14760                    }
14761                }
14762            }
14763
14764            if only_carets {
14765                for selection in &mut selections {
14766                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14767                    selection.start = word_range.start;
14768                    selection.end = word_range.end;
14769                    selection.goal = SelectionGoal::None;
14770                    selection.reversed = false;
14771                    self.select_match_ranges(
14772                        selection.start..selection.end,
14773                        selection.reversed,
14774                        action.replace_newest,
14775                        Some(Autoscroll::newest()),
14776                        window,
14777                        cx,
14778                    );
14779                }
14780                if selections.len() == 1 {
14781                    let selection = selections
14782                        .last()
14783                        .expect("ensured that there's only one selection");
14784                    let query = buffer
14785                        .text_for_range(selection.start..selection.end)
14786                        .collect::<String>();
14787                    let is_empty = query.is_empty();
14788                    let select_state = SelectNextState {
14789                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14790                        wordwise: true,
14791                        done: is_empty,
14792                    };
14793                    self.select_prev_state = Some(select_state);
14794                } else {
14795                    self.select_prev_state = None;
14796                }
14797            } else if let Some(selected_text) = selected_text {
14798                self.select_prev_state = Some(SelectNextState {
14799                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14800                    wordwise: false,
14801                    done: false,
14802                });
14803                self.select_previous(action, window, cx)?;
14804            }
14805        }
14806        Ok(())
14807    }
14808
14809    pub fn find_next_match(
14810        &mut self,
14811        _: &FindNextMatch,
14812        window: &mut Window,
14813        cx: &mut Context<Self>,
14814    ) -> Result<()> {
14815        let selections = self.selections.disjoint_anchors_arc();
14816        match selections.first() {
14817            Some(first) if selections.len() >= 2 => {
14818                self.change_selections(Default::default(), window, cx, |s| {
14819                    s.select_ranges([first.range()]);
14820                });
14821            }
14822            _ => self.select_next(
14823                &SelectNext {
14824                    replace_newest: true,
14825                },
14826                window,
14827                cx,
14828            )?,
14829        }
14830        Ok(())
14831    }
14832
14833    pub fn find_previous_match(
14834        &mut self,
14835        _: &FindPreviousMatch,
14836        window: &mut Window,
14837        cx: &mut Context<Self>,
14838    ) -> Result<()> {
14839        let selections = self.selections.disjoint_anchors_arc();
14840        match selections.last() {
14841            Some(last) if selections.len() >= 2 => {
14842                self.change_selections(Default::default(), window, cx, |s| {
14843                    s.select_ranges([last.range()]);
14844                });
14845            }
14846            _ => self.select_previous(
14847                &SelectPrevious {
14848                    replace_newest: true,
14849                },
14850                window,
14851                cx,
14852            )?,
14853        }
14854        Ok(())
14855    }
14856
14857    pub fn toggle_comments(
14858        &mut self,
14859        action: &ToggleComments,
14860        window: &mut Window,
14861        cx: &mut Context<Self>,
14862    ) {
14863        if self.read_only(cx) {
14864            return;
14865        }
14866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14867        let text_layout_details = &self.text_layout_details(window);
14868        self.transact(window, cx, |this, window, cx| {
14869            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14870            let mut edits = Vec::new();
14871            let mut selection_edit_ranges = Vec::new();
14872            let mut last_toggled_row = None;
14873            let snapshot = this.buffer.read(cx).read(cx);
14874            let empty_str: Arc<str> = Arc::default();
14875            let mut suffixes_inserted = Vec::new();
14876            let ignore_indent = action.ignore_indent;
14877
14878            fn comment_prefix_range(
14879                snapshot: &MultiBufferSnapshot,
14880                row: MultiBufferRow,
14881                comment_prefix: &str,
14882                comment_prefix_whitespace: &str,
14883                ignore_indent: bool,
14884            ) -> Range<Point> {
14885                let indent_size = if ignore_indent {
14886                    0
14887                } else {
14888                    snapshot.indent_size_for_line(row).len
14889                };
14890
14891                let start = Point::new(row.0, indent_size);
14892
14893                let mut line_bytes = snapshot
14894                    .bytes_in_range(start..snapshot.max_point())
14895                    .flatten()
14896                    .copied();
14897
14898                // If this line currently begins with the line comment prefix, then record
14899                // the range containing the prefix.
14900                if line_bytes
14901                    .by_ref()
14902                    .take(comment_prefix.len())
14903                    .eq(comment_prefix.bytes())
14904                {
14905                    // Include any whitespace that matches the comment prefix.
14906                    let matching_whitespace_len = line_bytes
14907                        .zip(comment_prefix_whitespace.bytes())
14908                        .take_while(|(a, b)| a == b)
14909                        .count() as u32;
14910                    let end = Point::new(
14911                        start.row,
14912                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14913                    );
14914                    start..end
14915                } else {
14916                    start..start
14917                }
14918            }
14919
14920            fn comment_suffix_range(
14921                snapshot: &MultiBufferSnapshot,
14922                row: MultiBufferRow,
14923                comment_suffix: &str,
14924                comment_suffix_has_leading_space: bool,
14925            ) -> Range<Point> {
14926                let end = Point::new(row.0, snapshot.line_len(row));
14927                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14928
14929                let mut line_end_bytes = snapshot
14930                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14931                    .flatten()
14932                    .copied();
14933
14934                let leading_space_len = if suffix_start_column > 0
14935                    && line_end_bytes.next() == Some(b' ')
14936                    && comment_suffix_has_leading_space
14937                {
14938                    1
14939                } else {
14940                    0
14941                };
14942
14943                // If this line currently begins with the line comment prefix, then record
14944                // the range containing the prefix.
14945                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14946                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14947                    start..end
14948                } else {
14949                    end..end
14950                }
14951            }
14952
14953            // TODO: Handle selections that cross excerpts
14954            for selection in &mut selections {
14955                let start_column = snapshot
14956                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14957                    .len;
14958                let language = if let Some(language) =
14959                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14960                {
14961                    language
14962                } else {
14963                    continue;
14964                };
14965
14966                selection_edit_ranges.clear();
14967
14968                // If multiple selections contain a given row, avoid processing that
14969                // row more than once.
14970                let mut start_row = MultiBufferRow(selection.start.row);
14971                if last_toggled_row == Some(start_row) {
14972                    start_row = start_row.next_row();
14973                }
14974                let end_row =
14975                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14976                        MultiBufferRow(selection.end.row - 1)
14977                    } else {
14978                        MultiBufferRow(selection.end.row)
14979                    };
14980                last_toggled_row = Some(end_row);
14981
14982                if start_row > end_row {
14983                    continue;
14984                }
14985
14986                // If the language has line comments, toggle those.
14987                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14988
14989                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14990                if ignore_indent {
14991                    full_comment_prefixes = full_comment_prefixes
14992                        .into_iter()
14993                        .map(|s| Arc::from(s.trim_end()))
14994                        .collect();
14995                }
14996
14997                if !full_comment_prefixes.is_empty() {
14998                    let first_prefix = full_comment_prefixes
14999                        .first()
15000                        .expect("prefixes is non-empty");
15001                    let prefix_trimmed_lengths = full_comment_prefixes
15002                        .iter()
15003                        .map(|p| p.trim_end_matches(' ').len())
15004                        .collect::<SmallVec<[usize; 4]>>();
15005
15006                    let mut all_selection_lines_are_comments = true;
15007
15008                    for row in start_row.0..=end_row.0 {
15009                        let row = MultiBufferRow(row);
15010                        if start_row < end_row && snapshot.is_line_blank(row) {
15011                            continue;
15012                        }
15013
15014                        let prefix_range = full_comment_prefixes
15015                            .iter()
15016                            .zip(prefix_trimmed_lengths.iter().copied())
15017                            .map(|(prefix, trimmed_prefix_len)| {
15018                                comment_prefix_range(
15019                                    snapshot.deref(),
15020                                    row,
15021                                    &prefix[..trimmed_prefix_len],
15022                                    &prefix[trimmed_prefix_len..],
15023                                    ignore_indent,
15024                                )
15025                            })
15026                            .max_by_key(|range| range.end.column - range.start.column)
15027                            .expect("prefixes is non-empty");
15028
15029                        if prefix_range.is_empty() {
15030                            all_selection_lines_are_comments = false;
15031                        }
15032
15033                        selection_edit_ranges.push(prefix_range);
15034                    }
15035
15036                    if all_selection_lines_are_comments {
15037                        edits.extend(
15038                            selection_edit_ranges
15039                                .iter()
15040                                .cloned()
15041                                .map(|range| (range, empty_str.clone())),
15042                        );
15043                    } else {
15044                        let min_column = selection_edit_ranges
15045                            .iter()
15046                            .map(|range| range.start.column)
15047                            .min()
15048                            .unwrap_or(0);
15049                        edits.extend(selection_edit_ranges.iter().map(|range| {
15050                            let position = Point::new(range.start.row, min_column);
15051                            (position..position, first_prefix.clone())
15052                        }));
15053                    }
15054                } else if let Some(BlockCommentConfig {
15055                    start: full_comment_prefix,
15056                    end: comment_suffix,
15057                    ..
15058                }) = language.block_comment()
15059                {
15060                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15061                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15062                    let prefix_range = comment_prefix_range(
15063                        snapshot.deref(),
15064                        start_row,
15065                        comment_prefix,
15066                        comment_prefix_whitespace,
15067                        ignore_indent,
15068                    );
15069                    let suffix_range = comment_suffix_range(
15070                        snapshot.deref(),
15071                        end_row,
15072                        comment_suffix.trim_start_matches(' '),
15073                        comment_suffix.starts_with(' '),
15074                    );
15075
15076                    if prefix_range.is_empty() || suffix_range.is_empty() {
15077                        edits.push((
15078                            prefix_range.start..prefix_range.start,
15079                            full_comment_prefix.clone(),
15080                        ));
15081                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15082                        suffixes_inserted.push((end_row, comment_suffix.len()));
15083                    } else {
15084                        edits.push((prefix_range, empty_str.clone()));
15085                        edits.push((suffix_range, empty_str.clone()));
15086                    }
15087                } else {
15088                    continue;
15089                }
15090            }
15091
15092            drop(snapshot);
15093            this.buffer.update(cx, |buffer, cx| {
15094                buffer.edit(edits, None, cx);
15095            });
15096
15097            // Adjust selections so that they end before any comment suffixes that
15098            // were inserted.
15099            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15100            let mut selections = this.selections.all::<Point>(cx);
15101            let snapshot = this.buffer.read(cx).read(cx);
15102            for selection in &mut selections {
15103                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15104                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15105                        Ordering::Less => {
15106                            suffixes_inserted.next();
15107                            continue;
15108                        }
15109                        Ordering::Greater => break,
15110                        Ordering::Equal => {
15111                            if selection.end.column == snapshot.line_len(row) {
15112                                if selection.is_empty() {
15113                                    selection.start.column -= suffix_len as u32;
15114                                }
15115                                selection.end.column -= suffix_len as u32;
15116                            }
15117                            break;
15118                        }
15119                    }
15120                }
15121            }
15122
15123            drop(snapshot);
15124            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15125
15126            let selections = this.selections.all::<Point>(cx);
15127            let selections_on_single_row = selections.windows(2).all(|selections| {
15128                selections[0].start.row == selections[1].start.row
15129                    && selections[0].end.row == selections[1].end.row
15130                    && selections[0].start.row == selections[0].end.row
15131            });
15132            let selections_selecting = selections
15133                .iter()
15134                .any(|selection| selection.start != selection.end);
15135            let advance_downwards = action.advance_downwards
15136                && selections_on_single_row
15137                && !selections_selecting
15138                && !matches!(this.mode, EditorMode::SingleLine);
15139
15140            if advance_downwards {
15141                let snapshot = this.buffer.read(cx).snapshot(cx);
15142
15143                this.change_selections(Default::default(), window, cx, |s| {
15144                    s.move_cursors_with(|display_snapshot, display_point, _| {
15145                        let mut point = display_point.to_point(display_snapshot);
15146                        point.row += 1;
15147                        point = snapshot.clip_point(point, Bias::Left);
15148                        let display_point = point.to_display_point(display_snapshot);
15149                        let goal = SelectionGoal::HorizontalPosition(
15150                            display_snapshot
15151                                .x_for_display_point(display_point, text_layout_details)
15152                                .into(),
15153                        );
15154                        (display_point, goal)
15155                    })
15156                });
15157            }
15158        });
15159    }
15160
15161    pub fn select_enclosing_symbol(
15162        &mut self,
15163        _: &SelectEnclosingSymbol,
15164        window: &mut Window,
15165        cx: &mut Context<Self>,
15166    ) {
15167        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15168
15169        let buffer = self.buffer.read(cx).snapshot(cx);
15170        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15171
15172        fn update_selection(
15173            selection: &Selection<usize>,
15174            buffer_snap: &MultiBufferSnapshot,
15175        ) -> Option<Selection<usize>> {
15176            let cursor = selection.head();
15177            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15178            for symbol in symbols.iter().rev() {
15179                let start = symbol.range.start.to_offset(buffer_snap);
15180                let end = symbol.range.end.to_offset(buffer_snap);
15181                let new_range = start..end;
15182                if start < selection.start || end > selection.end {
15183                    return Some(Selection {
15184                        id: selection.id,
15185                        start: new_range.start,
15186                        end: new_range.end,
15187                        goal: SelectionGoal::None,
15188                        reversed: selection.reversed,
15189                    });
15190                }
15191            }
15192            None
15193        }
15194
15195        let mut selected_larger_symbol = false;
15196        let new_selections = old_selections
15197            .iter()
15198            .map(|selection| match update_selection(selection, &buffer) {
15199                Some(new_selection) => {
15200                    if new_selection.range() != selection.range() {
15201                        selected_larger_symbol = true;
15202                    }
15203                    new_selection
15204                }
15205                None => selection.clone(),
15206            })
15207            .collect::<Vec<_>>();
15208
15209        if selected_larger_symbol {
15210            self.change_selections(Default::default(), window, cx, |s| {
15211                s.select(new_selections);
15212            });
15213        }
15214    }
15215
15216    pub fn select_larger_syntax_node(
15217        &mut self,
15218        _: &SelectLargerSyntaxNode,
15219        window: &mut Window,
15220        cx: &mut Context<Self>,
15221    ) {
15222        let Some(visible_row_count) = self.visible_row_count() else {
15223            return;
15224        };
15225        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15226        if old_selections.is_empty() {
15227            return;
15228        }
15229
15230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15231
15232        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15233        let buffer = self.buffer.read(cx).snapshot(cx);
15234
15235        let mut selected_larger_node = false;
15236        let mut new_selections = old_selections
15237            .iter()
15238            .map(|selection| {
15239                let old_range = selection.start..selection.end;
15240
15241                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15242                    // manually select word at selection
15243                    if ["string_content", "inline"].contains(&node.kind()) {
15244                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15245                        // ignore if word is already selected
15246                        if !word_range.is_empty() && old_range != word_range {
15247                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15248                            // only select word if start and end point belongs to same word
15249                            if word_range == last_word_range {
15250                                selected_larger_node = true;
15251                                return Selection {
15252                                    id: selection.id,
15253                                    start: word_range.start,
15254                                    end: word_range.end,
15255                                    goal: SelectionGoal::None,
15256                                    reversed: selection.reversed,
15257                                };
15258                            }
15259                        }
15260                    }
15261                }
15262
15263                let mut new_range = old_range.clone();
15264                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15265                    new_range = range;
15266                    if !node.is_named() {
15267                        continue;
15268                    }
15269                    if !display_map.intersects_fold(new_range.start)
15270                        && !display_map.intersects_fold(new_range.end)
15271                    {
15272                        break;
15273                    }
15274                }
15275
15276                selected_larger_node |= new_range != old_range;
15277                Selection {
15278                    id: selection.id,
15279                    start: new_range.start,
15280                    end: new_range.end,
15281                    goal: SelectionGoal::None,
15282                    reversed: selection.reversed,
15283                }
15284            })
15285            .collect::<Vec<_>>();
15286
15287        if !selected_larger_node {
15288            return; // don't put this call in the history
15289        }
15290
15291        // scroll based on transformation done to the last selection created by the user
15292        let (last_old, last_new) = old_selections
15293            .last()
15294            .zip(new_selections.last().cloned())
15295            .expect("old_selections isn't empty");
15296
15297        // revert selection
15298        let is_selection_reversed = {
15299            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15300            new_selections.last_mut().expect("checked above").reversed =
15301                should_newest_selection_be_reversed;
15302            should_newest_selection_be_reversed
15303        };
15304
15305        if selected_larger_node {
15306            self.select_syntax_node_history.disable_clearing = true;
15307            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15308                s.select(new_selections.clone());
15309            });
15310            self.select_syntax_node_history.disable_clearing = false;
15311        }
15312
15313        let start_row = last_new.start.to_display_point(&display_map).row().0;
15314        let end_row = last_new.end.to_display_point(&display_map).row().0;
15315        let selection_height = end_row - start_row + 1;
15316        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15317
15318        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15319        let scroll_behavior = if fits_on_the_screen {
15320            self.request_autoscroll(Autoscroll::fit(), cx);
15321            SelectSyntaxNodeScrollBehavior::FitSelection
15322        } else if is_selection_reversed {
15323            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15324            SelectSyntaxNodeScrollBehavior::CursorTop
15325        } else {
15326            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15327            SelectSyntaxNodeScrollBehavior::CursorBottom
15328        };
15329
15330        self.select_syntax_node_history.push((
15331            old_selections,
15332            scroll_behavior,
15333            is_selection_reversed,
15334        ));
15335    }
15336
15337    pub fn select_smaller_syntax_node(
15338        &mut self,
15339        _: &SelectSmallerSyntaxNode,
15340        window: &mut Window,
15341        cx: &mut Context<Self>,
15342    ) {
15343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15344
15345        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15346            self.select_syntax_node_history.pop()
15347        {
15348            if let Some(selection) = selections.last_mut() {
15349                selection.reversed = is_selection_reversed;
15350            }
15351
15352            self.select_syntax_node_history.disable_clearing = true;
15353            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15354                s.select(selections.to_vec());
15355            });
15356            self.select_syntax_node_history.disable_clearing = false;
15357
15358            match scroll_behavior {
15359                SelectSyntaxNodeScrollBehavior::CursorTop => {
15360                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15361                }
15362                SelectSyntaxNodeScrollBehavior::FitSelection => {
15363                    self.request_autoscroll(Autoscroll::fit(), cx);
15364                }
15365                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15366                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15367                }
15368            }
15369        }
15370    }
15371
15372    pub fn unwrap_syntax_node(
15373        &mut self,
15374        _: &UnwrapSyntaxNode,
15375        window: &mut Window,
15376        cx: &mut Context<Self>,
15377    ) {
15378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15379
15380        let buffer = self.buffer.read(cx).snapshot(cx);
15381        let selections = self
15382            .selections
15383            .all::<usize>(cx)
15384            .into_iter()
15385            // subtracting the offset requires sorting
15386            .sorted_by_key(|i| i.start);
15387
15388        let full_edits = selections
15389            .into_iter()
15390            .filter_map(|selection| {
15391                let child = if selection.is_empty()
15392                    && let Some((_, ancestor_range)) =
15393                        buffer.syntax_ancestor(selection.start..selection.end)
15394                {
15395                    ancestor_range
15396                } else {
15397                    selection.range()
15398                };
15399
15400                let mut parent = child.clone();
15401                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15402                    parent = ancestor_range;
15403                    if parent.start < child.start || parent.end > child.end {
15404                        break;
15405                    }
15406                }
15407
15408                if parent == child {
15409                    return None;
15410                }
15411                let text = buffer.text_for_range(child).collect::<String>();
15412                Some((selection.id, parent, text))
15413            })
15414            .collect::<Vec<_>>();
15415        if full_edits.is_empty() {
15416            return;
15417        }
15418
15419        self.transact(window, cx, |this, window, cx| {
15420            this.buffer.update(cx, |buffer, cx| {
15421                buffer.edit(
15422                    full_edits
15423                        .iter()
15424                        .map(|(_, p, t)| (p.clone(), t.clone()))
15425                        .collect::<Vec<_>>(),
15426                    None,
15427                    cx,
15428                );
15429            });
15430            this.change_selections(Default::default(), window, cx, |s| {
15431                let mut offset = 0;
15432                let mut selections = vec![];
15433                for (id, parent, text) in full_edits {
15434                    let start = parent.start - offset;
15435                    offset += parent.len() - text.len();
15436                    selections.push(Selection {
15437                        id,
15438                        start,
15439                        end: start + text.len(),
15440                        reversed: false,
15441                        goal: Default::default(),
15442                    });
15443                }
15444                s.select(selections);
15445            });
15446        });
15447    }
15448
15449    pub fn select_next_syntax_node(
15450        &mut self,
15451        _: &SelectNextSyntaxNode,
15452        window: &mut Window,
15453        cx: &mut Context<Self>,
15454    ) {
15455        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15456        if old_selections.is_empty() {
15457            return;
15458        }
15459
15460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15461
15462        let buffer = self.buffer.read(cx).snapshot(cx);
15463        let mut selected_sibling = false;
15464
15465        let new_selections = old_selections
15466            .iter()
15467            .map(|selection| {
15468                let old_range = selection.start..selection.end;
15469
15470                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15471                    let new_range = node.byte_range();
15472                    selected_sibling = true;
15473                    Selection {
15474                        id: selection.id,
15475                        start: new_range.start,
15476                        end: new_range.end,
15477                        goal: SelectionGoal::None,
15478                        reversed: selection.reversed,
15479                    }
15480                } else {
15481                    selection.clone()
15482                }
15483            })
15484            .collect::<Vec<_>>();
15485
15486        if selected_sibling {
15487            self.change_selections(
15488                SelectionEffects::scroll(Autoscroll::fit()),
15489                window,
15490                cx,
15491                |s| {
15492                    s.select(new_selections);
15493                },
15494            );
15495        }
15496    }
15497
15498    pub fn select_prev_syntax_node(
15499        &mut self,
15500        _: &SelectPreviousSyntaxNode,
15501        window: &mut Window,
15502        cx: &mut Context<Self>,
15503    ) {
15504        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15505        if old_selections.is_empty() {
15506            return;
15507        }
15508
15509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15510
15511        let buffer = self.buffer.read(cx).snapshot(cx);
15512        let mut selected_sibling = false;
15513
15514        let new_selections = old_selections
15515            .iter()
15516            .map(|selection| {
15517                let old_range = selection.start..selection.end;
15518
15519                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15520                    let new_range = node.byte_range();
15521                    selected_sibling = true;
15522                    Selection {
15523                        id: selection.id,
15524                        start: new_range.start,
15525                        end: new_range.end,
15526                        goal: SelectionGoal::None,
15527                        reversed: selection.reversed,
15528                    }
15529                } else {
15530                    selection.clone()
15531                }
15532            })
15533            .collect::<Vec<_>>();
15534
15535        if selected_sibling {
15536            self.change_selections(
15537                SelectionEffects::scroll(Autoscroll::fit()),
15538                window,
15539                cx,
15540                |s| {
15541                    s.select(new_selections);
15542                },
15543            );
15544        }
15545    }
15546
15547    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15548        if !EditorSettings::get_global(cx).gutter.runnables {
15549            self.clear_tasks();
15550            return Task::ready(());
15551        }
15552        let project = self.project().map(Entity::downgrade);
15553        let task_sources = self.lsp_task_sources(cx);
15554        let multi_buffer = self.buffer.downgrade();
15555        cx.spawn_in(window, async move |editor, cx| {
15556            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15557            let Some(project) = project.and_then(|p| p.upgrade()) else {
15558                return;
15559            };
15560            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15561                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15562            }) else {
15563                return;
15564            };
15565
15566            let hide_runnables = project
15567                .update(cx, |project, _| project.is_via_collab())
15568                .unwrap_or(true);
15569            if hide_runnables {
15570                return;
15571            }
15572            let new_rows =
15573                cx.background_spawn({
15574                    let snapshot = display_snapshot.clone();
15575                    async move {
15576                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15577                    }
15578                })
15579                    .await;
15580            let Ok(lsp_tasks) =
15581                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15582            else {
15583                return;
15584            };
15585            let lsp_tasks = lsp_tasks.await;
15586
15587            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15588                lsp_tasks
15589                    .into_iter()
15590                    .flat_map(|(kind, tasks)| {
15591                        tasks.into_iter().filter_map(move |(location, task)| {
15592                            Some((kind.clone(), location?, task))
15593                        })
15594                    })
15595                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15596                        let buffer = location.target.buffer;
15597                        let buffer_snapshot = buffer.read(cx).snapshot();
15598                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15599                            |(excerpt_id, snapshot, _)| {
15600                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15601                                    display_snapshot
15602                                        .buffer_snapshot()
15603                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15604                                } else {
15605                                    None
15606                                }
15607                            },
15608                        );
15609                        if let Some(offset) = offset {
15610                            let task_buffer_range =
15611                                location.target.range.to_point(&buffer_snapshot);
15612                            let context_buffer_range =
15613                                task_buffer_range.to_offset(&buffer_snapshot);
15614                            let context_range = BufferOffset(context_buffer_range.start)
15615                                ..BufferOffset(context_buffer_range.end);
15616
15617                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15618                                .or_insert_with(|| RunnableTasks {
15619                                    templates: Vec::new(),
15620                                    offset,
15621                                    column: task_buffer_range.start.column,
15622                                    extra_variables: HashMap::default(),
15623                                    context_range,
15624                                })
15625                                .templates
15626                                .push((kind, task.original_task().clone()));
15627                        }
15628
15629                        acc
15630                    })
15631            }) else {
15632                return;
15633            };
15634
15635            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15636                buffer.language_settings(cx).tasks.prefer_lsp
15637            }) else {
15638                return;
15639            };
15640
15641            let rows = Self::runnable_rows(
15642                project,
15643                display_snapshot,
15644                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15645                new_rows,
15646                cx.clone(),
15647            )
15648            .await;
15649            editor
15650                .update(cx, |editor, _| {
15651                    editor.clear_tasks();
15652                    for (key, mut value) in rows {
15653                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15654                            value.templates.extend(lsp_tasks.templates);
15655                        }
15656
15657                        editor.insert_tasks(key, value);
15658                    }
15659                    for (key, value) in lsp_tasks_by_rows {
15660                        editor.insert_tasks(key, value);
15661                    }
15662                })
15663                .ok();
15664        })
15665    }
15666    fn fetch_runnable_ranges(
15667        snapshot: &DisplaySnapshot,
15668        range: Range<Anchor>,
15669    ) -> Vec<language::RunnableRange> {
15670        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15671    }
15672
15673    fn runnable_rows(
15674        project: Entity<Project>,
15675        snapshot: DisplaySnapshot,
15676        prefer_lsp: bool,
15677        runnable_ranges: Vec<RunnableRange>,
15678        cx: AsyncWindowContext,
15679    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15680        cx.spawn(async move |cx| {
15681            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15682            for mut runnable in runnable_ranges {
15683                let Some(tasks) = cx
15684                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15685                    .ok()
15686                else {
15687                    continue;
15688                };
15689                let mut tasks = tasks.await;
15690
15691                if prefer_lsp {
15692                    tasks.retain(|(task_kind, _)| {
15693                        !matches!(task_kind, TaskSourceKind::Language { .. })
15694                    });
15695                }
15696                if tasks.is_empty() {
15697                    continue;
15698                }
15699
15700                let point = runnable
15701                    .run_range
15702                    .start
15703                    .to_point(&snapshot.buffer_snapshot());
15704                let Some(row) = snapshot
15705                    .buffer_snapshot()
15706                    .buffer_line_for_row(MultiBufferRow(point.row))
15707                    .map(|(_, range)| range.start.row)
15708                else {
15709                    continue;
15710                };
15711
15712                let context_range =
15713                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15714                runnable_rows.push((
15715                    (runnable.buffer_id, row),
15716                    RunnableTasks {
15717                        templates: tasks,
15718                        offset: snapshot
15719                            .buffer_snapshot()
15720                            .anchor_before(runnable.run_range.start),
15721                        context_range,
15722                        column: point.column,
15723                        extra_variables: runnable.extra_captures,
15724                    },
15725                ));
15726            }
15727            runnable_rows
15728        })
15729    }
15730
15731    fn templates_with_tags(
15732        project: &Entity<Project>,
15733        runnable: &mut Runnable,
15734        cx: &mut App,
15735    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15736        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15737            let (worktree_id, file) = project
15738                .buffer_for_id(runnable.buffer, cx)
15739                .and_then(|buffer| buffer.read(cx).file())
15740                .map(|file| (file.worktree_id(cx), file.clone()))
15741                .unzip();
15742
15743            (
15744                project.task_store().read(cx).task_inventory().cloned(),
15745                worktree_id,
15746                file,
15747            )
15748        });
15749
15750        let tags = mem::take(&mut runnable.tags);
15751        let language = runnable.language.clone();
15752        cx.spawn(async move |cx| {
15753            let mut templates_with_tags = Vec::new();
15754            if let Some(inventory) = inventory {
15755                for RunnableTag(tag) in tags {
15756                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15757                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15758                    }) else {
15759                        return templates_with_tags;
15760                    };
15761                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15762                        move |(_, template)| {
15763                            template.tags.iter().any(|source_tag| source_tag == &tag)
15764                        },
15765                    ));
15766                }
15767            }
15768            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15769
15770            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15771                // Strongest source wins; if we have worktree tag binding, prefer that to
15772                // global and language bindings;
15773                // if we have a global binding, prefer that to language binding.
15774                let first_mismatch = templates_with_tags
15775                    .iter()
15776                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15777                if let Some(index) = first_mismatch {
15778                    templates_with_tags.truncate(index);
15779                }
15780            }
15781
15782            templates_with_tags
15783        })
15784    }
15785
15786    pub fn move_to_enclosing_bracket(
15787        &mut self,
15788        _: &MoveToEnclosingBracket,
15789        window: &mut Window,
15790        cx: &mut Context<Self>,
15791    ) {
15792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15793        self.change_selections(Default::default(), window, cx, |s| {
15794            s.move_offsets_with(|snapshot, selection| {
15795                let Some(enclosing_bracket_ranges) =
15796                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15797                else {
15798                    return;
15799                };
15800
15801                let mut best_length = usize::MAX;
15802                let mut best_inside = false;
15803                let mut best_in_bracket_range = false;
15804                let mut best_destination = None;
15805                for (open, close) in enclosing_bracket_ranges {
15806                    let close = close.to_inclusive();
15807                    let length = close.end() - open.start;
15808                    let inside = selection.start >= open.end && selection.end <= *close.start();
15809                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15810                        || close.contains(&selection.head());
15811
15812                    // If best is next to a bracket and current isn't, skip
15813                    if !in_bracket_range && best_in_bracket_range {
15814                        continue;
15815                    }
15816
15817                    // Prefer smaller lengths unless best is inside and current isn't
15818                    if length > best_length && (best_inside || !inside) {
15819                        continue;
15820                    }
15821
15822                    best_length = length;
15823                    best_inside = inside;
15824                    best_in_bracket_range = in_bracket_range;
15825                    best_destination = Some(
15826                        if close.contains(&selection.start) && close.contains(&selection.end) {
15827                            if inside { open.end } else { open.start }
15828                        } else if inside {
15829                            *close.start()
15830                        } else {
15831                            *close.end()
15832                        },
15833                    );
15834                }
15835
15836                if let Some(destination) = best_destination {
15837                    selection.collapse_to(destination, SelectionGoal::None);
15838                }
15839            })
15840        });
15841    }
15842
15843    pub fn undo_selection(
15844        &mut self,
15845        _: &UndoSelection,
15846        window: &mut Window,
15847        cx: &mut Context<Self>,
15848    ) {
15849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15850        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15851            self.selection_history.mode = SelectionHistoryMode::Undoing;
15852            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15853                this.end_selection(window, cx);
15854                this.change_selections(
15855                    SelectionEffects::scroll(Autoscroll::newest()),
15856                    window,
15857                    cx,
15858                    |s| s.select_anchors(entry.selections.to_vec()),
15859                );
15860            });
15861            self.selection_history.mode = SelectionHistoryMode::Normal;
15862
15863            self.select_next_state = entry.select_next_state;
15864            self.select_prev_state = entry.select_prev_state;
15865            self.add_selections_state = entry.add_selections_state;
15866        }
15867    }
15868
15869    pub fn redo_selection(
15870        &mut self,
15871        _: &RedoSelection,
15872        window: &mut Window,
15873        cx: &mut Context<Self>,
15874    ) {
15875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15876        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15877            self.selection_history.mode = SelectionHistoryMode::Redoing;
15878            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15879                this.end_selection(window, cx);
15880                this.change_selections(
15881                    SelectionEffects::scroll(Autoscroll::newest()),
15882                    window,
15883                    cx,
15884                    |s| s.select_anchors(entry.selections.to_vec()),
15885                );
15886            });
15887            self.selection_history.mode = SelectionHistoryMode::Normal;
15888
15889            self.select_next_state = entry.select_next_state;
15890            self.select_prev_state = entry.select_prev_state;
15891            self.add_selections_state = entry.add_selections_state;
15892        }
15893    }
15894
15895    pub fn expand_excerpts(
15896        &mut self,
15897        action: &ExpandExcerpts,
15898        _: &mut Window,
15899        cx: &mut Context<Self>,
15900    ) {
15901        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15902    }
15903
15904    pub fn expand_excerpts_down(
15905        &mut self,
15906        action: &ExpandExcerptsDown,
15907        _: &mut Window,
15908        cx: &mut Context<Self>,
15909    ) {
15910        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15911    }
15912
15913    pub fn expand_excerpts_up(
15914        &mut self,
15915        action: &ExpandExcerptsUp,
15916        _: &mut Window,
15917        cx: &mut Context<Self>,
15918    ) {
15919        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15920    }
15921
15922    pub fn expand_excerpts_for_direction(
15923        &mut self,
15924        lines: u32,
15925        direction: ExpandExcerptDirection,
15926
15927        cx: &mut Context<Self>,
15928    ) {
15929        let selections = self.selections.disjoint_anchors_arc();
15930
15931        let lines = if lines == 0 {
15932            EditorSettings::get_global(cx).expand_excerpt_lines
15933        } else {
15934            lines
15935        };
15936
15937        self.buffer.update(cx, |buffer, cx| {
15938            let snapshot = buffer.snapshot(cx);
15939            let mut excerpt_ids = selections
15940                .iter()
15941                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15942                .collect::<Vec<_>>();
15943            excerpt_ids.sort();
15944            excerpt_ids.dedup();
15945            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15946        })
15947    }
15948
15949    pub fn expand_excerpt(
15950        &mut self,
15951        excerpt: ExcerptId,
15952        direction: ExpandExcerptDirection,
15953        window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) {
15956        let current_scroll_position = self.scroll_position(cx);
15957        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15958        let mut should_scroll_up = false;
15959
15960        if direction == ExpandExcerptDirection::Down {
15961            let multi_buffer = self.buffer.read(cx);
15962            let snapshot = multi_buffer.snapshot(cx);
15963            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15964                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15965                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15966            {
15967                let buffer_snapshot = buffer.read(cx).snapshot();
15968                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15969                let last_row = buffer_snapshot.max_point().row;
15970                let lines_below = last_row.saturating_sub(excerpt_end_row);
15971                should_scroll_up = lines_below >= lines_to_expand;
15972            }
15973        }
15974
15975        self.buffer.update(cx, |buffer, cx| {
15976            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15977        });
15978
15979        if should_scroll_up {
15980            let new_scroll_position =
15981                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15982            self.set_scroll_position(new_scroll_position, window, cx);
15983        }
15984    }
15985
15986    pub fn go_to_singleton_buffer_point(
15987        &mut self,
15988        point: Point,
15989        window: &mut Window,
15990        cx: &mut Context<Self>,
15991    ) {
15992        self.go_to_singleton_buffer_range(point..point, window, cx);
15993    }
15994
15995    pub fn go_to_singleton_buffer_range(
15996        &mut self,
15997        range: Range<Point>,
15998        window: &mut Window,
15999        cx: &mut Context<Self>,
16000    ) {
16001        let multibuffer = self.buffer().read(cx);
16002        let Some(buffer) = multibuffer.as_singleton() else {
16003            return;
16004        };
16005        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16006            return;
16007        };
16008        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16009            return;
16010        };
16011        self.change_selections(
16012            SelectionEffects::default().nav_history(true),
16013            window,
16014            cx,
16015            |s| s.select_anchor_ranges([start..end]),
16016        );
16017    }
16018
16019    pub fn go_to_diagnostic(
16020        &mut self,
16021        action: &GoToDiagnostic,
16022        window: &mut Window,
16023        cx: &mut Context<Self>,
16024    ) {
16025        if !self.diagnostics_enabled() {
16026            return;
16027        }
16028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16029        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16030    }
16031
16032    pub fn go_to_prev_diagnostic(
16033        &mut self,
16034        action: &GoToPreviousDiagnostic,
16035        window: &mut Window,
16036        cx: &mut Context<Self>,
16037    ) {
16038        if !self.diagnostics_enabled() {
16039            return;
16040        }
16041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16042        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16043    }
16044
16045    pub fn go_to_diagnostic_impl(
16046        &mut self,
16047        direction: Direction,
16048        severity: GoToDiagnosticSeverityFilter,
16049        window: &mut Window,
16050        cx: &mut Context<Self>,
16051    ) {
16052        let buffer = self.buffer.read(cx).snapshot(cx);
16053        let selection = self.selections.newest::<usize>(cx);
16054
16055        let mut active_group_id = None;
16056        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16057            && active_group.active_range.start.to_offset(&buffer) == selection.start
16058        {
16059            active_group_id = Some(active_group.group_id);
16060        }
16061
16062        fn filtered<'a>(
16063            snapshot: EditorSnapshot,
16064            severity: GoToDiagnosticSeverityFilter,
16065            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16066        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16067            diagnostics
16068                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16069                .filter(|entry| entry.range.start != entry.range.end)
16070                .filter(|entry| !entry.diagnostic.is_unnecessary)
16071                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16072        }
16073
16074        let snapshot = self.snapshot(window, cx);
16075        let before = filtered(
16076            snapshot.clone(),
16077            severity,
16078            buffer
16079                .diagnostics_in_range(0..selection.start)
16080                .filter(|entry| entry.range.start <= selection.start),
16081        );
16082        let after = filtered(
16083            snapshot,
16084            severity,
16085            buffer
16086                .diagnostics_in_range(selection.start..buffer.len())
16087                .filter(|entry| entry.range.start >= selection.start),
16088        );
16089
16090        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16091        if direction == Direction::Prev {
16092            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16093            {
16094                for diagnostic in prev_diagnostics.into_iter().rev() {
16095                    if diagnostic.range.start != selection.start
16096                        || active_group_id
16097                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16098                    {
16099                        found = Some(diagnostic);
16100                        break 'outer;
16101                    }
16102                }
16103            }
16104        } else {
16105            for diagnostic in after.chain(before) {
16106                if diagnostic.range.start != selection.start
16107                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16108                {
16109                    found = Some(diagnostic);
16110                    break;
16111                }
16112            }
16113        }
16114        let Some(next_diagnostic) = found else {
16115            return;
16116        };
16117
16118        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16119        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16120            return;
16121        };
16122        self.change_selections(Default::default(), window, cx, |s| {
16123            s.select_ranges(vec![
16124                next_diagnostic.range.start..next_diagnostic.range.start,
16125            ])
16126        });
16127        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16128        self.refresh_edit_prediction(false, true, window, cx);
16129    }
16130
16131    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16133        let snapshot = self.snapshot(window, cx);
16134        let selection = self.selections.newest::<Point>(cx);
16135        self.go_to_hunk_before_or_after_position(
16136            &snapshot,
16137            selection.head(),
16138            Direction::Next,
16139            window,
16140            cx,
16141        );
16142    }
16143
16144    pub fn go_to_hunk_before_or_after_position(
16145        &mut self,
16146        snapshot: &EditorSnapshot,
16147        position: Point,
16148        direction: Direction,
16149        window: &mut Window,
16150        cx: &mut Context<Editor>,
16151    ) {
16152        let row = if direction == Direction::Next {
16153            self.hunk_after_position(snapshot, position)
16154                .map(|hunk| hunk.row_range.start)
16155        } else {
16156            self.hunk_before_position(snapshot, position)
16157        };
16158
16159        if let Some(row) = row {
16160            let destination = Point::new(row.0, 0);
16161            let autoscroll = Autoscroll::center();
16162
16163            self.unfold_ranges(&[destination..destination], false, false, cx);
16164            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16165                s.select_ranges([destination..destination]);
16166            });
16167        }
16168    }
16169
16170    fn hunk_after_position(
16171        &mut self,
16172        snapshot: &EditorSnapshot,
16173        position: Point,
16174    ) -> Option<MultiBufferDiffHunk> {
16175        snapshot
16176            .buffer_snapshot()
16177            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16178            .find(|hunk| hunk.row_range.start.0 > position.row)
16179            .or_else(|| {
16180                snapshot
16181                    .buffer_snapshot()
16182                    .diff_hunks_in_range(Point::zero()..position)
16183                    .find(|hunk| hunk.row_range.end.0 < position.row)
16184            })
16185    }
16186
16187    fn go_to_prev_hunk(
16188        &mut self,
16189        _: &GoToPreviousHunk,
16190        window: &mut Window,
16191        cx: &mut Context<Self>,
16192    ) {
16193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16194        let snapshot = self.snapshot(window, cx);
16195        let selection = self.selections.newest::<Point>(cx);
16196        self.go_to_hunk_before_or_after_position(
16197            &snapshot,
16198            selection.head(),
16199            Direction::Prev,
16200            window,
16201            cx,
16202        );
16203    }
16204
16205    fn hunk_before_position(
16206        &mut self,
16207        snapshot: &EditorSnapshot,
16208        position: Point,
16209    ) -> Option<MultiBufferRow> {
16210        snapshot
16211            .buffer_snapshot()
16212            .diff_hunk_before(position)
16213            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16214    }
16215
16216    fn go_to_next_change(
16217        &mut self,
16218        _: &GoToNextChange,
16219        window: &mut Window,
16220        cx: &mut Context<Self>,
16221    ) {
16222        if let Some(selections) = self
16223            .change_list
16224            .next_change(1, Direction::Next)
16225            .map(|s| s.to_vec())
16226        {
16227            self.change_selections(Default::default(), window, cx, |s| {
16228                let map = s.display_map();
16229                s.select_display_ranges(selections.iter().map(|a| {
16230                    let point = a.to_display_point(&map);
16231                    point..point
16232                }))
16233            })
16234        }
16235    }
16236
16237    fn go_to_previous_change(
16238        &mut self,
16239        _: &GoToPreviousChange,
16240        window: &mut Window,
16241        cx: &mut Context<Self>,
16242    ) {
16243        if let Some(selections) = self
16244            .change_list
16245            .next_change(1, Direction::Prev)
16246            .map(|s| s.to_vec())
16247        {
16248            self.change_selections(Default::default(), window, cx, |s| {
16249                let map = s.display_map();
16250                s.select_display_ranges(selections.iter().map(|a| {
16251                    let point = a.to_display_point(&map);
16252                    point..point
16253                }))
16254            })
16255        }
16256    }
16257
16258    pub fn go_to_next_document_highlight(
16259        &mut self,
16260        _: &GoToNextDocumentHighlight,
16261        window: &mut Window,
16262        cx: &mut Context<Self>,
16263    ) {
16264        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16265    }
16266
16267    pub fn go_to_prev_document_highlight(
16268        &mut self,
16269        _: &GoToPreviousDocumentHighlight,
16270        window: &mut Window,
16271        cx: &mut Context<Self>,
16272    ) {
16273        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16274    }
16275
16276    pub fn go_to_document_highlight_before_or_after_position(
16277        &mut self,
16278        direction: Direction,
16279        window: &mut Window,
16280        cx: &mut Context<Editor>,
16281    ) {
16282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16283        let snapshot = self.snapshot(window, cx);
16284        let buffer = &snapshot.buffer_snapshot();
16285        let position = self.selections.newest::<Point>(cx).head();
16286        let anchor_position = buffer.anchor_after(position);
16287
16288        // Get all document highlights (both read and write)
16289        let mut all_highlights = Vec::new();
16290
16291        if let Some((_, read_highlights)) = self
16292            .background_highlights
16293            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16294        {
16295            all_highlights.extend(read_highlights.iter());
16296        }
16297
16298        if let Some((_, write_highlights)) = self
16299            .background_highlights
16300            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16301        {
16302            all_highlights.extend(write_highlights.iter());
16303        }
16304
16305        if all_highlights.is_empty() {
16306            return;
16307        }
16308
16309        // Sort highlights by position
16310        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16311
16312        let target_highlight = match direction {
16313            Direction::Next => {
16314                // Find the first highlight after the current position
16315                all_highlights
16316                    .iter()
16317                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16318            }
16319            Direction::Prev => {
16320                // Find the last highlight before the current position
16321                all_highlights
16322                    .iter()
16323                    .rev()
16324                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16325            }
16326        };
16327
16328        if let Some(highlight) = target_highlight {
16329            let destination = highlight.start.to_point(buffer);
16330            let autoscroll = Autoscroll::center();
16331
16332            self.unfold_ranges(&[destination..destination], false, false, cx);
16333            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16334                s.select_ranges([destination..destination]);
16335            });
16336        }
16337    }
16338
16339    fn go_to_line<T: 'static>(
16340        &mut self,
16341        position: Anchor,
16342        highlight_color: Option<Hsla>,
16343        window: &mut Window,
16344        cx: &mut Context<Self>,
16345    ) {
16346        let snapshot = self.snapshot(window, cx).display_snapshot;
16347        let position = position.to_point(&snapshot.buffer_snapshot());
16348        let start = snapshot
16349            .buffer_snapshot()
16350            .clip_point(Point::new(position.row, 0), Bias::Left);
16351        let end = start + Point::new(1, 0);
16352        let start = snapshot.buffer_snapshot().anchor_before(start);
16353        let end = snapshot.buffer_snapshot().anchor_before(end);
16354
16355        self.highlight_rows::<T>(
16356            start..end,
16357            highlight_color
16358                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16359            Default::default(),
16360            cx,
16361        );
16362
16363        if self.buffer.read(cx).is_singleton() {
16364            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16365        }
16366    }
16367
16368    pub fn go_to_definition(
16369        &mut self,
16370        _: &GoToDefinition,
16371        window: &mut Window,
16372        cx: &mut Context<Self>,
16373    ) -> Task<Result<Navigated>> {
16374        let definition =
16375            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16376        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16377        cx.spawn_in(window, async move |editor, cx| {
16378            if definition.await? == Navigated::Yes {
16379                return Ok(Navigated::Yes);
16380            }
16381            match fallback_strategy {
16382                GoToDefinitionFallback::None => Ok(Navigated::No),
16383                GoToDefinitionFallback::FindAllReferences => {
16384                    match editor.update_in(cx, |editor, window, cx| {
16385                        editor.find_all_references(&FindAllReferences, window, cx)
16386                    })? {
16387                        Some(references) => references.await,
16388                        None => Ok(Navigated::No),
16389                    }
16390                }
16391            }
16392        })
16393    }
16394
16395    pub fn go_to_declaration(
16396        &mut self,
16397        _: &GoToDeclaration,
16398        window: &mut Window,
16399        cx: &mut Context<Self>,
16400    ) -> Task<Result<Navigated>> {
16401        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16402    }
16403
16404    pub fn go_to_declaration_split(
16405        &mut self,
16406        _: &GoToDeclaration,
16407        window: &mut Window,
16408        cx: &mut Context<Self>,
16409    ) -> Task<Result<Navigated>> {
16410        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16411    }
16412
16413    pub fn go_to_implementation(
16414        &mut self,
16415        _: &GoToImplementation,
16416        window: &mut Window,
16417        cx: &mut Context<Self>,
16418    ) -> Task<Result<Navigated>> {
16419        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16420    }
16421
16422    pub fn go_to_implementation_split(
16423        &mut self,
16424        _: &GoToImplementationSplit,
16425        window: &mut Window,
16426        cx: &mut Context<Self>,
16427    ) -> Task<Result<Navigated>> {
16428        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16429    }
16430
16431    pub fn go_to_type_definition(
16432        &mut self,
16433        _: &GoToTypeDefinition,
16434        window: &mut Window,
16435        cx: &mut Context<Self>,
16436    ) -> Task<Result<Navigated>> {
16437        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16438    }
16439
16440    pub fn go_to_definition_split(
16441        &mut self,
16442        _: &GoToDefinitionSplit,
16443        window: &mut Window,
16444        cx: &mut Context<Self>,
16445    ) -> Task<Result<Navigated>> {
16446        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16447    }
16448
16449    pub fn go_to_type_definition_split(
16450        &mut self,
16451        _: &GoToTypeDefinitionSplit,
16452        window: &mut Window,
16453        cx: &mut Context<Self>,
16454    ) -> Task<Result<Navigated>> {
16455        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16456    }
16457
16458    fn go_to_definition_of_kind(
16459        &mut self,
16460        kind: GotoDefinitionKind,
16461        split: bool,
16462        window: &mut Window,
16463        cx: &mut Context<Self>,
16464    ) -> Task<Result<Navigated>> {
16465        let Some(provider) = self.semantics_provider.clone() else {
16466            return Task::ready(Ok(Navigated::No));
16467        };
16468        let head = self.selections.newest::<usize>(cx).head();
16469        let buffer = self.buffer.read(cx);
16470        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16471            return Task::ready(Ok(Navigated::No));
16472        };
16473        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16474            return Task::ready(Ok(Navigated::No));
16475        };
16476
16477        cx.spawn_in(window, async move |editor, cx| {
16478            let Some(definitions) = definitions.await? else {
16479                return Ok(Navigated::No);
16480            };
16481            let navigated = editor
16482                .update_in(cx, |editor, window, cx| {
16483                    editor.navigate_to_hover_links(
16484                        Some(kind),
16485                        definitions
16486                            .into_iter()
16487                            .filter(|location| {
16488                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16489                            })
16490                            .map(HoverLink::Text)
16491                            .collect::<Vec<_>>(),
16492                        split,
16493                        window,
16494                        cx,
16495                    )
16496                })?
16497                .await?;
16498            anyhow::Ok(navigated)
16499        })
16500    }
16501
16502    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16503        let selection = self.selections.newest_anchor();
16504        let head = selection.head();
16505        let tail = selection.tail();
16506
16507        let Some((buffer, start_position)) =
16508            self.buffer.read(cx).text_anchor_for_position(head, cx)
16509        else {
16510            return;
16511        };
16512
16513        let end_position = if head != tail {
16514            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16515                return;
16516            };
16517            Some(pos)
16518        } else {
16519            None
16520        };
16521
16522        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16523            let url = if let Some(end_pos) = end_position {
16524                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16525            } else {
16526                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16527            };
16528
16529            if let Some(url) = url {
16530                cx.update(|window, cx| {
16531                    if parse_zed_link(&url, cx).is_some() {
16532                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16533                    } else {
16534                        cx.open_url(&url);
16535                    }
16536                })?;
16537            }
16538
16539            anyhow::Ok(())
16540        });
16541
16542        url_finder.detach();
16543    }
16544
16545    pub fn open_selected_filename(
16546        &mut self,
16547        _: &OpenSelectedFilename,
16548        window: &mut Window,
16549        cx: &mut Context<Self>,
16550    ) {
16551        let Some(workspace) = self.workspace() else {
16552            return;
16553        };
16554
16555        let position = self.selections.newest_anchor().head();
16556
16557        let Some((buffer, buffer_position)) =
16558            self.buffer.read(cx).text_anchor_for_position(position, cx)
16559        else {
16560            return;
16561        };
16562
16563        let project = self.project.clone();
16564
16565        cx.spawn_in(window, async move |_, cx| {
16566            let result = find_file(&buffer, project, buffer_position, cx).await;
16567
16568            if let Some((_, path)) = result {
16569                workspace
16570                    .update_in(cx, |workspace, window, cx| {
16571                        workspace.open_resolved_path(path, window, cx)
16572                    })?
16573                    .await?;
16574            }
16575            anyhow::Ok(())
16576        })
16577        .detach();
16578    }
16579
16580    pub(crate) fn navigate_to_hover_links(
16581        &mut self,
16582        kind: Option<GotoDefinitionKind>,
16583        definitions: Vec<HoverLink>,
16584        split: bool,
16585        window: &mut Window,
16586        cx: &mut Context<Editor>,
16587    ) -> Task<Result<Navigated>> {
16588        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16589        let mut first_url_or_file = None;
16590        let definitions: Vec<_> = definitions
16591            .into_iter()
16592            .filter_map(|def| match def {
16593                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16594                HoverLink::InlayHint(lsp_location, server_id) => {
16595                    let computation =
16596                        self.compute_target_location(lsp_location, server_id, window, cx);
16597                    Some(cx.background_spawn(computation))
16598                }
16599                HoverLink::Url(url) => {
16600                    first_url_or_file = Some(Either::Left(url));
16601                    None
16602                }
16603                HoverLink::File(path) => {
16604                    first_url_or_file = Some(Either::Right(path));
16605                    None
16606                }
16607            })
16608            .collect();
16609
16610        let workspace = self.workspace();
16611
16612        cx.spawn_in(window, async move |editor, cx| {
16613            let locations: Vec<Location> = future::join_all(definitions)
16614                .await
16615                .into_iter()
16616                .filter_map(|location| location.transpose())
16617                .collect::<Result<_>>()
16618                .context("location tasks")?;
16619            let mut locations = cx.update(|_, cx| {
16620                locations
16621                    .into_iter()
16622                    .map(|location| {
16623                        let buffer = location.buffer.read(cx);
16624                        (location.buffer, location.range.to_point(buffer))
16625                    })
16626                    .into_group_map()
16627            })?;
16628            let mut num_locations = 0;
16629            for ranges in locations.values_mut() {
16630                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16631                ranges.dedup();
16632                num_locations += ranges.len();
16633            }
16634
16635            if num_locations > 1 {
16636                let Some(workspace) = workspace else {
16637                    return Ok(Navigated::No);
16638                };
16639
16640                let tab_kind = match kind {
16641                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16642                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16643                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16644                    Some(GotoDefinitionKind::Type) => "Types",
16645                };
16646                let title = editor
16647                    .update_in(cx, |_, _, cx| {
16648                        let target = locations
16649                            .iter()
16650                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16651                            .map(|(buffer, location)| {
16652                                buffer
16653                                    .read(cx)
16654                                    .text_for_range(location.clone())
16655                                    .collect::<String>()
16656                            })
16657                            .filter(|text| !text.contains('\n'))
16658                            .unique()
16659                            .take(3)
16660                            .join(", ");
16661                        if target.is_empty() {
16662                            tab_kind.to_owned()
16663                        } else {
16664                            format!("{tab_kind} for {target}")
16665                        }
16666                    })
16667                    .context("buffer title")?;
16668
16669                let opened = workspace
16670                    .update_in(cx, |workspace, window, cx| {
16671                        Self::open_locations_in_multibuffer(
16672                            workspace,
16673                            locations,
16674                            title,
16675                            split,
16676                            MultibufferSelectionMode::First,
16677                            window,
16678                            cx,
16679                        )
16680                    })
16681                    .is_ok();
16682
16683                anyhow::Ok(Navigated::from_bool(opened))
16684            } else if num_locations == 0 {
16685                // If there is one url or file, open it directly
16686                match first_url_or_file {
16687                    Some(Either::Left(url)) => {
16688                        cx.update(|_, cx| cx.open_url(&url))?;
16689                        Ok(Navigated::Yes)
16690                    }
16691                    Some(Either::Right(path)) => {
16692                        let Some(workspace) = workspace else {
16693                            return Ok(Navigated::No);
16694                        };
16695
16696                        workspace
16697                            .update_in(cx, |workspace, window, cx| {
16698                                workspace.open_resolved_path(path, window, cx)
16699                            })?
16700                            .await?;
16701                        Ok(Navigated::Yes)
16702                    }
16703                    None => Ok(Navigated::No),
16704                }
16705            } else {
16706                let Some(workspace) = workspace else {
16707                    return Ok(Navigated::No);
16708                };
16709
16710                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16711                let target_range = target_ranges.first().unwrap().clone();
16712
16713                editor.update_in(cx, |editor, window, cx| {
16714                    let range = target_range.to_point(target_buffer.read(cx));
16715                    let range = editor.range_for_match(&range);
16716                    let range = collapse_multiline_range(range);
16717
16718                    if !split
16719                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16720                    {
16721                        editor.go_to_singleton_buffer_range(range, window, cx);
16722                    } else {
16723                        let pane = workspace.read(cx).active_pane().clone();
16724                        window.defer(cx, move |window, cx| {
16725                            let target_editor: Entity<Self> =
16726                                workspace.update(cx, |workspace, cx| {
16727                                    let pane = if split {
16728                                        workspace.adjacent_pane(window, cx)
16729                                    } else {
16730                                        workspace.active_pane().clone()
16731                                    };
16732
16733                                    workspace.open_project_item(
16734                                        pane,
16735                                        target_buffer.clone(),
16736                                        true,
16737                                        true,
16738                                        window,
16739                                        cx,
16740                                    )
16741                                });
16742                            target_editor.update(cx, |target_editor, cx| {
16743                                // When selecting a definition in a different buffer, disable the nav history
16744                                // to avoid creating a history entry at the previous cursor location.
16745                                pane.update(cx, |pane, _| pane.disable_history());
16746                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16747                                pane.update(cx, |pane, _| pane.enable_history());
16748                            });
16749                        });
16750                    }
16751                    Navigated::Yes
16752                })
16753            }
16754        })
16755    }
16756
16757    fn compute_target_location(
16758        &self,
16759        lsp_location: lsp::Location,
16760        server_id: LanguageServerId,
16761        window: &mut Window,
16762        cx: &mut Context<Self>,
16763    ) -> Task<anyhow::Result<Option<Location>>> {
16764        let Some(project) = self.project.clone() else {
16765            return Task::ready(Ok(None));
16766        };
16767
16768        cx.spawn_in(window, async move |editor, cx| {
16769            let location_task = editor.update(cx, |_, cx| {
16770                project.update(cx, |project, cx| {
16771                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16772                })
16773            })?;
16774            let location = Some({
16775                let target_buffer_handle = location_task.await.context("open local buffer")?;
16776                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16777                    let target_start = target_buffer
16778                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16779                    let target_end = target_buffer
16780                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16781                    target_buffer.anchor_after(target_start)
16782                        ..target_buffer.anchor_before(target_end)
16783                })?;
16784                Location {
16785                    buffer: target_buffer_handle,
16786                    range,
16787                }
16788            });
16789            Ok(location)
16790        })
16791    }
16792
16793    pub fn find_all_references(
16794        &mut self,
16795        _: &FindAllReferences,
16796        window: &mut Window,
16797        cx: &mut Context<Self>,
16798    ) -> Option<Task<Result<Navigated>>> {
16799        let selection = self.selections.newest::<usize>(cx);
16800        let multi_buffer = self.buffer.read(cx);
16801        let head = selection.head();
16802
16803        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16804        let head_anchor = multi_buffer_snapshot.anchor_at(
16805            head,
16806            if head < selection.tail() {
16807                Bias::Right
16808            } else {
16809                Bias::Left
16810            },
16811        );
16812
16813        match self
16814            .find_all_references_task_sources
16815            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16816        {
16817            Ok(_) => {
16818                log::info!(
16819                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16820                );
16821                return None;
16822            }
16823            Err(i) => {
16824                self.find_all_references_task_sources.insert(i, head_anchor);
16825            }
16826        }
16827
16828        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16829        let workspace = self.workspace()?;
16830        let project = workspace.read(cx).project().clone();
16831        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16832        Some(cx.spawn_in(window, async move |editor, cx| {
16833            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16834                if let Ok(i) = editor
16835                    .find_all_references_task_sources
16836                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16837                {
16838                    editor.find_all_references_task_sources.remove(i);
16839                }
16840            });
16841
16842            let Some(locations) = references.await? else {
16843                return anyhow::Ok(Navigated::No);
16844            };
16845            let mut locations = cx.update(|_, cx| {
16846                locations
16847                    .into_iter()
16848                    .map(|location| {
16849                        let buffer = location.buffer.read(cx);
16850                        (location.buffer, location.range.to_point(buffer))
16851                    })
16852                    .into_group_map()
16853            })?;
16854            if locations.is_empty() {
16855                return anyhow::Ok(Navigated::No);
16856            }
16857            for ranges in locations.values_mut() {
16858                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16859                ranges.dedup();
16860            }
16861
16862            workspace.update_in(cx, |workspace, window, cx| {
16863                let target = locations
16864                    .iter()
16865                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16866                    .map(|(buffer, location)| {
16867                        buffer
16868                            .read(cx)
16869                            .text_for_range(location.clone())
16870                            .collect::<String>()
16871                    })
16872                    .filter(|text| !text.contains('\n'))
16873                    .unique()
16874                    .take(3)
16875                    .join(", ");
16876                let title = if target.is_empty() {
16877                    "References".to_owned()
16878                } else {
16879                    format!("References to {target}")
16880                };
16881                Self::open_locations_in_multibuffer(
16882                    workspace,
16883                    locations,
16884                    title,
16885                    false,
16886                    MultibufferSelectionMode::First,
16887                    window,
16888                    cx,
16889                );
16890                Navigated::Yes
16891            })
16892        }))
16893    }
16894
16895    /// Opens a multibuffer with the given project locations in it
16896    pub fn open_locations_in_multibuffer(
16897        workspace: &mut Workspace,
16898        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16899        title: String,
16900        split: bool,
16901        multibuffer_selection_mode: MultibufferSelectionMode,
16902        window: &mut Window,
16903        cx: &mut Context<Workspace>,
16904    ) {
16905        if locations.is_empty() {
16906            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16907            return;
16908        }
16909
16910        let capability = workspace.project().read(cx).capability();
16911        let mut ranges = <Vec<Range<Anchor>>>::new();
16912
16913        // a key to find existing multibuffer editors with the same set of locations
16914        // to prevent us from opening more and more multibuffer tabs for searches and the like
16915        let mut key = (title.clone(), vec![]);
16916        let excerpt_buffer = cx.new(|cx| {
16917            let key = &mut key.1;
16918            let mut multibuffer = MultiBuffer::new(capability);
16919            for (buffer, mut ranges_for_buffer) in locations {
16920                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16921                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16922                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16923                    PathKey::for_buffer(&buffer, cx),
16924                    buffer.clone(),
16925                    ranges_for_buffer,
16926                    multibuffer_context_lines(cx),
16927                    cx,
16928                );
16929                ranges.extend(new_ranges)
16930            }
16931
16932            multibuffer.with_title(title)
16933        });
16934        let existing = workspace.active_pane().update(cx, |pane, cx| {
16935            pane.items()
16936                .filter_map(|item| item.downcast::<Editor>())
16937                .find(|editor| {
16938                    editor
16939                        .read(cx)
16940                        .lookup_key
16941                        .as_ref()
16942                        .and_then(|it| {
16943                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16944                        })
16945                        .is_some_and(|it| *it == key)
16946                })
16947        });
16948        let editor = existing.unwrap_or_else(|| {
16949            cx.new(|cx| {
16950                let mut editor = Editor::for_multibuffer(
16951                    excerpt_buffer,
16952                    Some(workspace.project().clone()),
16953                    window,
16954                    cx,
16955                );
16956                editor.lookup_key = Some(Box::new(key));
16957                editor
16958            })
16959        });
16960        editor.update(cx, |editor, cx| {
16961            match multibuffer_selection_mode {
16962                MultibufferSelectionMode::First => {
16963                    if let Some(first_range) = ranges.first() {
16964                        editor.change_selections(
16965                            SelectionEffects::no_scroll(),
16966                            window,
16967                            cx,
16968                            |selections| {
16969                                selections.clear_disjoint();
16970                                selections
16971                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16972                            },
16973                        );
16974                    }
16975                    editor.highlight_background::<Self>(
16976                        &ranges,
16977                        |theme| theme.colors().editor_highlighted_line_background,
16978                        cx,
16979                    );
16980                }
16981                MultibufferSelectionMode::All => {
16982                    editor.change_selections(
16983                        SelectionEffects::no_scroll(),
16984                        window,
16985                        cx,
16986                        |selections| {
16987                            selections.clear_disjoint();
16988                            selections.select_anchor_ranges(ranges);
16989                        },
16990                    );
16991                }
16992            }
16993            editor.register_buffers_with_language_servers(cx);
16994        });
16995
16996        let item = Box::new(editor);
16997        let item_id = item.item_id();
16998
16999        if split {
17000            let pane = workspace.adjacent_pane(window, cx);
17001            workspace.add_item(pane, item, None, true, true, window, cx);
17002        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17003            let (preview_item_id, preview_item_idx) =
17004                workspace.active_pane().read_with(cx, |pane, _| {
17005                    (pane.preview_item_id(), pane.preview_item_idx())
17006                });
17007
17008            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17009
17010            if let Some(preview_item_id) = preview_item_id {
17011                workspace.active_pane().update(cx, |pane, cx| {
17012                    pane.remove_item(preview_item_id, false, false, window, cx);
17013                });
17014            }
17015        } else {
17016            workspace.add_item_to_active_pane(item, None, true, window, cx);
17017        }
17018        workspace.active_pane().update(cx, |pane, cx| {
17019            pane.set_preview_item_id(Some(item_id), cx);
17020        });
17021    }
17022
17023    pub fn rename(
17024        &mut self,
17025        _: &Rename,
17026        window: &mut Window,
17027        cx: &mut Context<Self>,
17028    ) -> Option<Task<Result<()>>> {
17029        use language::ToOffset as _;
17030
17031        let provider = self.semantics_provider.clone()?;
17032        let selection = self.selections.newest_anchor().clone();
17033        let (cursor_buffer, cursor_buffer_position) = self
17034            .buffer
17035            .read(cx)
17036            .text_anchor_for_position(selection.head(), cx)?;
17037        let (tail_buffer, cursor_buffer_position_end) = self
17038            .buffer
17039            .read(cx)
17040            .text_anchor_for_position(selection.tail(), cx)?;
17041        if tail_buffer != cursor_buffer {
17042            return None;
17043        }
17044
17045        let snapshot = cursor_buffer.read(cx).snapshot();
17046        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17047        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17048        let prepare_rename = provider
17049            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17050            .unwrap_or_else(|| Task::ready(Ok(None)));
17051        drop(snapshot);
17052
17053        Some(cx.spawn_in(window, async move |this, cx| {
17054            let rename_range = if let Some(range) = prepare_rename.await? {
17055                Some(range)
17056            } else {
17057                this.update(cx, |this, cx| {
17058                    let buffer = this.buffer.read(cx).snapshot(cx);
17059                    let mut buffer_highlights = this
17060                        .document_highlights_for_position(selection.head(), &buffer)
17061                        .filter(|highlight| {
17062                            highlight.start.excerpt_id == selection.head().excerpt_id
17063                                && highlight.end.excerpt_id == selection.head().excerpt_id
17064                        });
17065                    buffer_highlights
17066                        .next()
17067                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17068                })?
17069            };
17070            if let Some(rename_range) = rename_range {
17071                this.update_in(cx, |this, window, cx| {
17072                    let snapshot = cursor_buffer.read(cx).snapshot();
17073                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17074                    let cursor_offset_in_rename_range =
17075                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17076                    let cursor_offset_in_rename_range_end =
17077                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17078
17079                    this.take_rename(false, window, cx);
17080                    let buffer = this.buffer.read(cx).read(cx);
17081                    let cursor_offset = selection.head().to_offset(&buffer);
17082                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17083                    let rename_end = rename_start + rename_buffer_range.len();
17084                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17085                    let mut old_highlight_id = None;
17086                    let old_name: Arc<str> = buffer
17087                        .chunks(rename_start..rename_end, true)
17088                        .map(|chunk| {
17089                            if old_highlight_id.is_none() {
17090                                old_highlight_id = chunk.syntax_highlight_id;
17091                            }
17092                            chunk.text
17093                        })
17094                        .collect::<String>()
17095                        .into();
17096
17097                    drop(buffer);
17098
17099                    // Position the selection in the rename editor so that it matches the current selection.
17100                    this.show_local_selections = false;
17101                    let rename_editor = cx.new(|cx| {
17102                        let mut editor = Editor::single_line(window, cx);
17103                        editor.buffer.update(cx, |buffer, cx| {
17104                            buffer.edit([(0..0, old_name.clone())], None, cx)
17105                        });
17106                        let rename_selection_range = match cursor_offset_in_rename_range
17107                            .cmp(&cursor_offset_in_rename_range_end)
17108                        {
17109                            Ordering::Equal => {
17110                                editor.select_all(&SelectAll, window, cx);
17111                                return editor;
17112                            }
17113                            Ordering::Less => {
17114                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17115                            }
17116                            Ordering::Greater => {
17117                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17118                            }
17119                        };
17120                        if rename_selection_range.end > old_name.len() {
17121                            editor.select_all(&SelectAll, window, cx);
17122                        } else {
17123                            editor.change_selections(Default::default(), window, cx, |s| {
17124                                s.select_ranges([rename_selection_range]);
17125                            });
17126                        }
17127                        editor
17128                    });
17129                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17130                        if e == &EditorEvent::Focused {
17131                            cx.emit(EditorEvent::FocusedIn)
17132                        }
17133                    })
17134                    .detach();
17135
17136                    let write_highlights =
17137                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17138                    let read_highlights =
17139                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17140                    let ranges = write_highlights
17141                        .iter()
17142                        .flat_map(|(_, ranges)| ranges.iter())
17143                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17144                        .cloned()
17145                        .collect();
17146
17147                    this.highlight_text::<Rename>(
17148                        ranges,
17149                        HighlightStyle {
17150                            fade_out: Some(0.6),
17151                            ..Default::default()
17152                        },
17153                        cx,
17154                    );
17155                    let rename_focus_handle = rename_editor.focus_handle(cx);
17156                    window.focus(&rename_focus_handle);
17157                    let block_id = this.insert_blocks(
17158                        [BlockProperties {
17159                            style: BlockStyle::Flex,
17160                            placement: BlockPlacement::Below(range.start),
17161                            height: Some(1),
17162                            render: Arc::new({
17163                                let rename_editor = rename_editor.clone();
17164                                move |cx: &mut BlockContext| {
17165                                    let mut text_style = cx.editor_style.text.clone();
17166                                    if let Some(highlight_style) = old_highlight_id
17167                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17168                                    {
17169                                        text_style = text_style.highlight(highlight_style);
17170                                    }
17171                                    div()
17172                                        .block_mouse_except_scroll()
17173                                        .pl(cx.anchor_x)
17174                                        .child(EditorElement::new(
17175                                            &rename_editor,
17176                                            EditorStyle {
17177                                                background: cx.theme().system().transparent,
17178                                                local_player: cx.editor_style.local_player,
17179                                                text: text_style,
17180                                                scrollbar_width: cx.editor_style.scrollbar_width,
17181                                                syntax: cx.editor_style.syntax.clone(),
17182                                                status: cx.editor_style.status.clone(),
17183                                                inlay_hints_style: HighlightStyle {
17184                                                    font_weight: Some(FontWeight::BOLD),
17185                                                    ..make_inlay_hints_style(cx.app)
17186                                                },
17187                                                edit_prediction_styles: make_suggestion_styles(
17188                                                    cx.app,
17189                                                ),
17190                                                ..EditorStyle::default()
17191                                            },
17192                                        ))
17193                                        .into_any_element()
17194                                }
17195                            }),
17196                            priority: 0,
17197                        }],
17198                        Some(Autoscroll::fit()),
17199                        cx,
17200                    )[0];
17201                    this.pending_rename = Some(RenameState {
17202                        range,
17203                        old_name,
17204                        editor: rename_editor,
17205                        block_id,
17206                    });
17207                })?;
17208            }
17209
17210            Ok(())
17211        }))
17212    }
17213
17214    pub fn confirm_rename(
17215        &mut self,
17216        _: &ConfirmRename,
17217        window: &mut Window,
17218        cx: &mut Context<Self>,
17219    ) -> Option<Task<Result<()>>> {
17220        let rename = self.take_rename(false, window, cx)?;
17221        let workspace = self.workspace()?.downgrade();
17222        let (buffer, start) = self
17223            .buffer
17224            .read(cx)
17225            .text_anchor_for_position(rename.range.start, cx)?;
17226        let (end_buffer, _) = self
17227            .buffer
17228            .read(cx)
17229            .text_anchor_for_position(rename.range.end, cx)?;
17230        if buffer != end_buffer {
17231            return None;
17232        }
17233
17234        let old_name = rename.old_name;
17235        let new_name = rename.editor.read(cx).text(cx);
17236
17237        let rename = self.semantics_provider.as_ref()?.perform_rename(
17238            &buffer,
17239            start,
17240            new_name.clone(),
17241            cx,
17242        )?;
17243
17244        Some(cx.spawn_in(window, async move |editor, cx| {
17245            let project_transaction = rename.await?;
17246            Self::open_project_transaction(
17247                &editor,
17248                workspace,
17249                project_transaction,
17250                format!("Rename: {}{}", old_name, new_name),
17251                cx,
17252            )
17253            .await?;
17254
17255            editor.update(cx, |editor, cx| {
17256                editor.refresh_document_highlights(cx);
17257            })?;
17258            Ok(())
17259        }))
17260    }
17261
17262    fn take_rename(
17263        &mut self,
17264        moving_cursor: bool,
17265        window: &mut Window,
17266        cx: &mut Context<Self>,
17267    ) -> Option<RenameState> {
17268        let rename = self.pending_rename.take()?;
17269        if rename.editor.focus_handle(cx).is_focused(window) {
17270            window.focus(&self.focus_handle);
17271        }
17272
17273        self.remove_blocks(
17274            [rename.block_id].into_iter().collect(),
17275            Some(Autoscroll::fit()),
17276            cx,
17277        );
17278        self.clear_highlights::<Rename>(cx);
17279        self.show_local_selections = true;
17280
17281        if moving_cursor {
17282            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17283                editor.selections.newest::<usize>(cx).head()
17284            });
17285
17286            // Update the selection to match the position of the selection inside
17287            // the rename editor.
17288            let snapshot = self.buffer.read(cx).read(cx);
17289            let rename_range = rename.range.to_offset(&snapshot);
17290            let cursor_in_editor = snapshot
17291                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17292                .min(rename_range.end);
17293            drop(snapshot);
17294
17295            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17296                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17297            });
17298        } else {
17299            self.refresh_document_highlights(cx);
17300        }
17301
17302        Some(rename)
17303    }
17304
17305    pub fn pending_rename(&self) -> Option<&RenameState> {
17306        self.pending_rename.as_ref()
17307    }
17308
17309    fn format(
17310        &mut self,
17311        _: &Format,
17312        window: &mut Window,
17313        cx: &mut Context<Self>,
17314    ) -> Option<Task<Result<()>>> {
17315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17316
17317        let project = match &self.project {
17318            Some(project) => project.clone(),
17319            None => return None,
17320        };
17321
17322        Some(self.perform_format(
17323            project,
17324            FormatTrigger::Manual,
17325            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17326            window,
17327            cx,
17328        ))
17329    }
17330
17331    fn format_selections(
17332        &mut self,
17333        _: &FormatSelections,
17334        window: &mut Window,
17335        cx: &mut Context<Self>,
17336    ) -> Option<Task<Result<()>>> {
17337        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17338
17339        let project = match &self.project {
17340            Some(project) => project.clone(),
17341            None => return None,
17342        };
17343
17344        let ranges = self
17345            .selections
17346            .all_adjusted(cx)
17347            .into_iter()
17348            .map(|selection| selection.range())
17349            .collect_vec();
17350
17351        Some(self.perform_format(
17352            project,
17353            FormatTrigger::Manual,
17354            FormatTarget::Ranges(ranges),
17355            window,
17356            cx,
17357        ))
17358    }
17359
17360    fn perform_format(
17361        &mut self,
17362        project: Entity<Project>,
17363        trigger: FormatTrigger,
17364        target: FormatTarget,
17365        window: &mut Window,
17366        cx: &mut Context<Self>,
17367    ) -> Task<Result<()>> {
17368        let buffer = self.buffer.clone();
17369        let (buffers, target) = match target {
17370            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17371            FormatTarget::Ranges(selection_ranges) => {
17372                let multi_buffer = buffer.read(cx);
17373                let snapshot = multi_buffer.read(cx);
17374                let mut buffers = HashSet::default();
17375                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17376                    BTreeMap::new();
17377                for selection_range in selection_ranges {
17378                    for (buffer, buffer_range, _) in
17379                        snapshot.range_to_buffer_ranges(selection_range)
17380                    {
17381                        let buffer_id = buffer.remote_id();
17382                        let start = buffer.anchor_before(buffer_range.start);
17383                        let end = buffer.anchor_after(buffer_range.end);
17384                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17385                        buffer_id_to_ranges
17386                            .entry(buffer_id)
17387                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17388                            .or_insert_with(|| vec![start..end]);
17389                    }
17390                }
17391                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17392            }
17393        };
17394
17395        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17396        let selections_prev = transaction_id_prev
17397            .and_then(|transaction_id_prev| {
17398                // default to selections as they were after the last edit, if we have them,
17399                // instead of how they are now.
17400                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17401                // will take you back to where you made the last edit, instead of staying where you scrolled
17402                self.selection_history
17403                    .transaction(transaction_id_prev)
17404                    .map(|t| t.0.clone())
17405            })
17406            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17407
17408        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17409        let format = project.update(cx, |project, cx| {
17410            project.format(buffers, target, true, trigger, cx)
17411        });
17412
17413        cx.spawn_in(window, async move |editor, cx| {
17414            let transaction = futures::select_biased! {
17415                transaction = format.log_err().fuse() => transaction,
17416                () = timeout => {
17417                    log::warn!("timed out waiting for formatting");
17418                    None
17419                }
17420            };
17421
17422            buffer
17423                .update(cx, |buffer, cx| {
17424                    if let Some(transaction) = transaction
17425                        && !buffer.is_singleton()
17426                    {
17427                        buffer.push_transaction(&transaction.0, cx);
17428                    }
17429                    cx.notify();
17430                })
17431                .ok();
17432
17433            if let Some(transaction_id_now) =
17434                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17435            {
17436                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17437                if has_new_transaction {
17438                    _ = editor.update(cx, |editor, _| {
17439                        editor
17440                            .selection_history
17441                            .insert_transaction(transaction_id_now, selections_prev);
17442                    });
17443                }
17444            }
17445
17446            Ok(())
17447        })
17448    }
17449
17450    fn organize_imports(
17451        &mut self,
17452        _: &OrganizeImports,
17453        window: &mut Window,
17454        cx: &mut Context<Self>,
17455    ) -> Option<Task<Result<()>>> {
17456        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17457        let project = match &self.project {
17458            Some(project) => project.clone(),
17459            None => return None,
17460        };
17461        Some(self.perform_code_action_kind(
17462            project,
17463            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17464            window,
17465            cx,
17466        ))
17467    }
17468
17469    fn perform_code_action_kind(
17470        &mut self,
17471        project: Entity<Project>,
17472        kind: CodeActionKind,
17473        window: &mut Window,
17474        cx: &mut Context<Self>,
17475    ) -> Task<Result<()>> {
17476        let buffer = self.buffer.clone();
17477        let buffers = buffer.read(cx).all_buffers();
17478        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17479        let apply_action = project.update(cx, |project, cx| {
17480            project.apply_code_action_kind(buffers, kind, true, cx)
17481        });
17482        cx.spawn_in(window, async move |_, cx| {
17483            let transaction = futures::select_biased! {
17484                () = timeout => {
17485                    log::warn!("timed out waiting for executing code action");
17486                    None
17487                }
17488                transaction = apply_action.log_err().fuse() => transaction,
17489            };
17490            buffer
17491                .update(cx, |buffer, cx| {
17492                    // check if we need this
17493                    if let Some(transaction) = transaction
17494                        && !buffer.is_singleton()
17495                    {
17496                        buffer.push_transaction(&transaction.0, cx);
17497                    }
17498                    cx.notify();
17499                })
17500                .ok();
17501            Ok(())
17502        })
17503    }
17504
17505    pub fn restart_language_server(
17506        &mut self,
17507        _: &RestartLanguageServer,
17508        _: &mut Window,
17509        cx: &mut Context<Self>,
17510    ) {
17511        if let Some(project) = self.project.clone() {
17512            self.buffer.update(cx, |multi_buffer, cx| {
17513                project.update(cx, |project, cx| {
17514                    project.restart_language_servers_for_buffers(
17515                        multi_buffer.all_buffers().into_iter().collect(),
17516                        HashSet::default(),
17517                        cx,
17518                    );
17519                });
17520            })
17521        }
17522    }
17523
17524    pub fn stop_language_server(
17525        &mut self,
17526        _: &StopLanguageServer,
17527        _: &mut Window,
17528        cx: &mut Context<Self>,
17529    ) {
17530        if let Some(project) = self.project.clone() {
17531            self.buffer.update(cx, |multi_buffer, cx| {
17532                project.update(cx, |project, cx| {
17533                    project.stop_language_servers_for_buffers(
17534                        multi_buffer.all_buffers().into_iter().collect(),
17535                        HashSet::default(),
17536                        cx,
17537                    );
17538                    cx.emit(project::Event::RefreshInlayHints);
17539                });
17540            });
17541        }
17542    }
17543
17544    fn cancel_language_server_work(
17545        workspace: &mut Workspace,
17546        _: &actions::CancelLanguageServerWork,
17547        _: &mut Window,
17548        cx: &mut Context<Workspace>,
17549    ) {
17550        let project = workspace.project();
17551        let buffers = workspace
17552            .active_item(cx)
17553            .and_then(|item| item.act_as::<Editor>(cx))
17554            .map_or(HashSet::default(), |editor| {
17555                editor.read(cx).buffer.read(cx).all_buffers()
17556            });
17557        project.update(cx, |project, cx| {
17558            project.cancel_language_server_work_for_buffers(buffers, cx);
17559        });
17560    }
17561
17562    fn show_character_palette(
17563        &mut self,
17564        _: &ShowCharacterPalette,
17565        window: &mut Window,
17566        _: &mut Context<Self>,
17567    ) {
17568        window.show_character_palette();
17569    }
17570
17571    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17572        if !self.diagnostics_enabled() {
17573            return;
17574        }
17575
17576        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17577            let buffer = self.buffer.read(cx).snapshot(cx);
17578            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17579            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17580            let is_valid = buffer
17581                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17582                .any(|entry| {
17583                    entry.diagnostic.is_primary
17584                        && !entry.range.is_empty()
17585                        && entry.range.start == primary_range_start
17586                        && entry.diagnostic.message == active_diagnostics.active_message
17587                });
17588
17589            if !is_valid {
17590                self.dismiss_diagnostics(cx);
17591            }
17592        }
17593    }
17594
17595    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17596        match &self.active_diagnostics {
17597            ActiveDiagnostic::Group(group) => Some(group),
17598            _ => None,
17599        }
17600    }
17601
17602    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17603        if !self.diagnostics_enabled() {
17604            return;
17605        }
17606        self.dismiss_diagnostics(cx);
17607        self.active_diagnostics = ActiveDiagnostic::All;
17608    }
17609
17610    fn activate_diagnostics(
17611        &mut self,
17612        buffer_id: BufferId,
17613        diagnostic: DiagnosticEntryRef<'_, usize>,
17614        window: &mut Window,
17615        cx: &mut Context<Self>,
17616    ) {
17617        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17618            return;
17619        }
17620        self.dismiss_diagnostics(cx);
17621        let snapshot = self.snapshot(window, cx);
17622        let buffer = self.buffer.read(cx).snapshot(cx);
17623        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17624            return;
17625        };
17626
17627        let diagnostic_group = buffer
17628            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17629            .collect::<Vec<_>>();
17630
17631        let blocks =
17632            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17633
17634        let blocks = self.display_map.update(cx, |display_map, cx| {
17635            display_map.insert_blocks(blocks, cx).into_iter().collect()
17636        });
17637        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17638            active_range: buffer.anchor_before(diagnostic.range.start)
17639                ..buffer.anchor_after(diagnostic.range.end),
17640            active_message: diagnostic.diagnostic.message.clone(),
17641            group_id: diagnostic.diagnostic.group_id,
17642            blocks,
17643        });
17644        cx.notify();
17645    }
17646
17647    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17648        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17649            return;
17650        };
17651
17652        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17653        if let ActiveDiagnostic::Group(group) = prev {
17654            self.display_map.update(cx, |display_map, cx| {
17655                display_map.remove_blocks(group.blocks, cx);
17656            });
17657            cx.notify();
17658        }
17659    }
17660
17661    /// Disable inline diagnostics rendering for this editor.
17662    pub fn disable_inline_diagnostics(&mut self) {
17663        self.inline_diagnostics_enabled = false;
17664        self.inline_diagnostics_update = Task::ready(());
17665        self.inline_diagnostics.clear();
17666    }
17667
17668    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17669        self.diagnostics_enabled = false;
17670        self.dismiss_diagnostics(cx);
17671        self.inline_diagnostics_update = Task::ready(());
17672        self.inline_diagnostics.clear();
17673    }
17674
17675    pub fn disable_word_completions(&mut self) {
17676        self.word_completions_enabled = false;
17677    }
17678
17679    pub fn diagnostics_enabled(&self) -> bool {
17680        self.diagnostics_enabled && self.mode.is_full()
17681    }
17682
17683    pub fn inline_diagnostics_enabled(&self) -> bool {
17684        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17685    }
17686
17687    pub fn show_inline_diagnostics(&self) -> bool {
17688        self.show_inline_diagnostics
17689    }
17690
17691    pub fn toggle_inline_diagnostics(
17692        &mut self,
17693        _: &ToggleInlineDiagnostics,
17694        window: &mut Window,
17695        cx: &mut Context<Editor>,
17696    ) {
17697        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17698        self.refresh_inline_diagnostics(false, window, cx);
17699    }
17700
17701    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17702        self.diagnostics_max_severity = severity;
17703        self.display_map.update(cx, |display_map, _| {
17704            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17705        });
17706    }
17707
17708    pub fn toggle_diagnostics(
17709        &mut self,
17710        _: &ToggleDiagnostics,
17711        window: &mut Window,
17712        cx: &mut Context<Editor>,
17713    ) {
17714        if !self.diagnostics_enabled() {
17715            return;
17716        }
17717
17718        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17719            EditorSettings::get_global(cx)
17720                .diagnostics_max_severity
17721                .filter(|severity| severity != &DiagnosticSeverity::Off)
17722                .unwrap_or(DiagnosticSeverity::Hint)
17723        } else {
17724            DiagnosticSeverity::Off
17725        };
17726        self.set_max_diagnostics_severity(new_severity, cx);
17727        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17728            self.active_diagnostics = ActiveDiagnostic::None;
17729            self.inline_diagnostics_update = Task::ready(());
17730            self.inline_diagnostics.clear();
17731        } else {
17732            self.refresh_inline_diagnostics(false, window, cx);
17733        }
17734
17735        cx.notify();
17736    }
17737
17738    pub fn toggle_minimap(
17739        &mut self,
17740        _: &ToggleMinimap,
17741        window: &mut Window,
17742        cx: &mut Context<Editor>,
17743    ) {
17744        if self.supports_minimap(cx) {
17745            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17746        }
17747    }
17748
17749    fn refresh_inline_diagnostics(
17750        &mut self,
17751        debounce: bool,
17752        window: &mut Window,
17753        cx: &mut Context<Self>,
17754    ) {
17755        let max_severity = ProjectSettings::get_global(cx)
17756            .diagnostics
17757            .inline
17758            .max_severity
17759            .unwrap_or(self.diagnostics_max_severity);
17760
17761        if !self.inline_diagnostics_enabled()
17762            || !self.show_inline_diagnostics
17763            || max_severity == DiagnosticSeverity::Off
17764        {
17765            self.inline_diagnostics_update = Task::ready(());
17766            self.inline_diagnostics.clear();
17767            return;
17768        }
17769
17770        let debounce_ms = ProjectSettings::get_global(cx)
17771            .diagnostics
17772            .inline
17773            .update_debounce_ms;
17774        let debounce = if debounce && debounce_ms > 0 {
17775            Some(Duration::from_millis(debounce_ms))
17776        } else {
17777            None
17778        };
17779        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17780            if let Some(debounce) = debounce {
17781                cx.background_executor().timer(debounce).await;
17782            }
17783            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17784                editor
17785                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17786                    .ok()
17787            }) else {
17788                return;
17789            };
17790
17791            let new_inline_diagnostics = cx
17792                .background_spawn(async move {
17793                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17794                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17795                        let message = diagnostic_entry
17796                            .diagnostic
17797                            .message
17798                            .split_once('\n')
17799                            .map(|(line, _)| line)
17800                            .map(SharedString::new)
17801                            .unwrap_or_else(|| {
17802                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17803                            });
17804                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17805                        let (Ok(i) | Err(i)) = inline_diagnostics
17806                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17807                        inline_diagnostics.insert(
17808                            i,
17809                            (
17810                                start_anchor,
17811                                InlineDiagnostic {
17812                                    message,
17813                                    group_id: diagnostic_entry.diagnostic.group_id,
17814                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17815                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17816                                    severity: diagnostic_entry.diagnostic.severity,
17817                                },
17818                            ),
17819                        );
17820                    }
17821                    inline_diagnostics
17822                })
17823                .await;
17824
17825            editor
17826                .update(cx, |editor, cx| {
17827                    editor.inline_diagnostics = new_inline_diagnostics;
17828                    cx.notify();
17829                })
17830                .ok();
17831        });
17832    }
17833
17834    fn pull_diagnostics(
17835        &mut self,
17836        buffer_id: Option<BufferId>,
17837        window: &Window,
17838        cx: &mut Context<Self>,
17839    ) -> Option<()> {
17840        if !self.mode().is_full() {
17841            return None;
17842        }
17843        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17844            .diagnostics
17845            .lsp_pull_diagnostics;
17846        if !pull_diagnostics_settings.enabled {
17847            return None;
17848        }
17849        let project = self.project()?.downgrade();
17850        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17851        let mut buffers = self.buffer.read(cx).all_buffers();
17852        if let Some(buffer_id) = buffer_id {
17853            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17854        }
17855
17856        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17857            cx.background_executor().timer(debounce).await;
17858
17859            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17860                buffers
17861                    .into_iter()
17862                    .filter_map(|buffer| {
17863                        project
17864                            .update(cx, |project, cx| {
17865                                project.lsp_store().update(cx, |lsp_store, cx| {
17866                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17867                                })
17868                            })
17869                            .ok()
17870                    })
17871                    .collect::<FuturesUnordered<_>>()
17872            }) else {
17873                return;
17874            };
17875
17876            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17877                match pull_task {
17878                    Ok(()) => {
17879                        if editor
17880                            .update_in(cx, |editor, window, cx| {
17881                                editor.update_diagnostics_state(window, cx);
17882                            })
17883                            .is_err()
17884                        {
17885                            return;
17886                        }
17887                    }
17888                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17889                }
17890            }
17891        });
17892
17893        Some(())
17894    }
17895
17896    pub fn set_selections_from_remote(
17897        &mut self,
17898        selections: Vec<Selection<Anchor>>,
17899        pending_selection: Option<Selection<Anchor>>,
17900        window: &mut Window,
17901        cx: &mut Context<Self>,
17902    ) {
17903        let old_cursor_position = self.selections.newest_anchor().head();
17904        self.selections.change_with(cx, |s| {
17905            s.select_anchors(selections);
17906            if let Some(pending_selection) = pending_selection {
17907                s.set_pending(pending_selection, SelectMode::Character);
17908            } else {
17909                s.clear_pending();
17910            }
17911        });
17912        self.selections_did_change(
17913            false,
17914            &old_cursor_position,
17915            SelectionEffects::default(),
17916            window,
17917            cx,
17918        );
17919    }
17920
17921    pub fn transact(
17922        &mut self,
17923        window: &mut Window,
17924        cx: &mut Context<Self>,
17925        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17926    ) -> Option<TransactionId> {
17927        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17928            this.start_transaction_at(Instant::now(), window, cx);
17929            update(this, window, cx);
17930            this.end_transaction_at(Instant::now(), cx)
17931        })
17932    }
17933
17934    pub fn start_transaction_at(
17935        &mut self,
17936        now: Instant,
17937        window: &mut Window,
17938        cx: &mut Context<Self>,
17939    ) -> Option<TransactionId> {
17940        self.end_selection(window, cx);
17941        if let Some(tx_id) = self
17942            .buffer
17943            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17944        {
17945            self.selection_history
17946                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17947            cx.emit(EditorEvent::TransactionBegun {
17948                transaction_id: tx_id,
17949            });
17950            Some(tx_id)
17951        } else {
17952            None
17953        }
17954    }
17955
17956    pub fn end_transaction_at(
17957        &mut self,
17958        now: Instant,
17959        cx: &mut Context<Self>,
17960    ) -> Option<TransactionId> {
17961        if let Some(transaction_id) = self
17962            .buffer
17963            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17964        {
17965            if let Some((_, end_selections)) =
17966                self.selection_history.transaction_mut(transaction_id)
17967            {
17968                *end_selections = Some(self.selections.disjoint_anchors_arc());
17969            } else {
17970                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17971            }
17972
17973            cx.emit(EditorEvent::Edited { transaction_id });
17974            Some(transaction_id)
17975        } else {
17976            None
17977        }
17978    }
17979
17980    pub fn modify_transaction_selection_history(
17981        &mut self,
17982        transaction_id: TransactionId,
17983        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17984    ) -> bool {
17985        self.selection_history
17986            .transaction_mut(transaction_id)
17987            .map(modify)
17988            .is_some()
17989    }
17990
17991    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17992        if self.selection_mark_mode {
17993            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17994                s.move_with(|_, sel| {
17995                    sel.collapse_to(sel.head(), SelectionGoal::None);
17996                });
17997            })
17998        }
17999        self.selection_mark_mode = true;
18000        cx.notify();
18001    }
18002
18003    pub fn swap_selection_ends(
18004        &mut self,
18005        _: &actions::SwapSelectionEnds,
18006        window: &mut Window,
18007        cx: &mut Context<Self>,
18008    ) {
18009        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18010            s.move_with(|_, sel| {
18011                if sel.start != sel.end {
18012                    sel.reversed = !sel.reversed
18013                }
18014            });
18015        });
18016        self.request_autoscroll(Autoscroll::newest(), cx);
18017        cx.notify();
18018    }
18019
18020    pub fn toggle_focus(
18021        workspace: &mut Workspace,
18022        _: &actions::ToggleFocus,
18023        window: &mut Window,
18024        cx: &mut Context<Workspace>,
18025    ) {
18026        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18027            return;
18028        };
18029        workspace.activate_item(&item, true, true, window, cx);
18030    }
18031
18032    pub fn toggle_fold(
18033        &mut self,
18034        _: &actions::ToggleFold,
18035        window: &mut Window,
18036        cx: &mut Context<Self>,
18037    ) {
18038        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18039            let selection = self.selections.newest::<Point>(cx);
18040
18041            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18042            let range = if selection.is_empty() {
18043                let point = selection.head().to_display_point(&display_map);
18044                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18045                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18046                    .to_point(&display_map);
18047                start..end
18048            } else {
18049                selection.range()
18050            };
18051            if display_map.folds_in_range(range).next().is_some() {
18052                self.unfold_lines(&Default::default(), window, cx)
18053            } else {
18054                self.fold(&Default::default(), window, cx)
18055            }
18056        } else {
18057            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18058            let buffer_ids: HashSet<_> = self
18059                .selections
18060                .disjoint_anchor_ranges()
18061                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18062                .collect();
18063
18064            let should_unfold = buffer_ids
18065                .iter()
18066                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18067
18068            for buffer_id in buffer_ids {
18069                if should_unfold {
18070                    self.unfold_buffer(buffer_id, cx);
18071                } else {
18072                    self.fold_buffer(buffer_id, cx);
18073                }
18074            }
18075        }
18076    }
18077
18078    pub fn toggle_fold_recursive(
18079        &mut self,
18080        _: &actions::ToggleFoldRecursive,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        let selection = self.selections.newest::<Point>(cx);
18085
18086        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18087        let range = if selection.is_empty() {
18088            let point = selection.head().to_display_point(&display_map);
18089            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18090            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18091                .to_point(&display_map);
18092            start..end
18093        } else {
18094            selection.range()
18095        };
18096        if display_map.folds_in_range(range).next().is_some() {
18097            self.unfold_recursive(&Default::default(), window, cx)
18098        } else {
18099            self.fold_recursive(&Default::default(), window, cx)
18100        }
18101    }
18102
18103    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18104        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18105            let mut to_fold = Vec::new();
18106            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18107            let selections = self.selections.all_adjusted(cx);
18108
18109            for selection in selections {
18110                let range = selection.range().sorted();
18111                let buffer_start_row = range.start.row;
18112
18113                if range.start.row != range.end.row {
18114                    let mut found = false;
18115                    let mut row = range.start.row;
18116                    while row <= range.end.row {
18117                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18118                        {
18119                            found = true;
18120                            row = crease.range().end.row + 1;
18121                            to_fold.push(crease);
18122                        } else {
18123                            row += 1
18124                        }
18125                    }
18126                    if found {
18127                        continue;
18128                    }
18129                }
18130
18131                for row in (0..=range.start.row).rev() {
18132                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18133                        && crease.range().end.row >= buffer_start_row
18134                    {
18135                        to_fold.push(crease);
18136                        if row <= range.start.row {
18137                            break;
18138                        }
18139                    }
18140                }
18141            }
18142
18143            self.fold_creases(to_fold, true, window, cx);
18144        } else {
18145            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18146            let buffer_ids = self
18147                .selections
18148                .disjoint_anchor_ranges()
18149                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18150                .collect::<HashSet<_>>();
18151            for buffer_id in buffer_ids {
18152                self.fold_buffer(buffer_id, cx);
18153            }
18154        }
18155    }
18156
18157    pub fn toggle_fold_all(
18158        &mut self,
18159        _: &actions::ToggleFoldAll,
18160        window: &mut Window,
18161        cx: &mut Context<Self>,
18162    ) {
18163        if self.buffer.read(cx).is_singleton() {
18164            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18165            let has_folds = display_map
18166                .folds_in_range(0..display_map.buffer_snapshot().len())
18167                .next()
18168                .is_some();
18169
18170            if has_folds {
18171                self.unfold_all(&actions::UnfoldAll, window, cx);
18172            } else {
18173                self.fold_all(&actions::FoldAll, window, cx);
18174            }
18175        } else {
18176            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18177            let should_unfold = buffer_ids
18178                .iter()
18179                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18180
18181            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18182                editor
18183                    .update_in(cx, |editor, _, cx| {
18184                        for buffer_id in buffer_ids {
18185                            if should_unfold {
18186                                editor.unfold_buffer(buffer_id, cx);
18187                            } else {
18188                                editor.fold_buffer(buffer_id, cx);
18189                            }
18190                        }
18191                    })
18192                    .ok();
18193            });
18194        }
18195    }
18196
18197    fn fold_at_level(
18198        &mut self,
18199        fold_at: &FoldAtLevel,
18200        window: &mut Window,
18201        cx: &mut Context<Self>,
18202    ) {
18203        if !self.buffer.read(cx).is_singleton() {
18204            return;
18205        }
18206
18207        let fold_at_level = fold_at.0;
18208        let snapshot = self.buffer.read(cx).snapshot(cx);
18209        let mut to_fold = Vec::new();
18210        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18211
18212        let row_ranges_to_keep: Vec<Range<u32>> = self
18213            .selections
18214            .all::<Point>(cx)
18215            .into_iter()
18216            .map(|sel| sel.start.row..sel.end.row)
18217            .collect();
18218
18219        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18220            while start_row < end_row {
18221                match self
18222                    .snapshot(window, cx)
18223                    .crease_for_buffer_row(MultiBufferRow(start_row))
18224                {
18225                    Some(crease) => {
18226                        let nested_start_row = crease.range().start.row + 1;
18227                        let nested_end_row = crease.range().end.row;
18228
18229                        if current_level < fold_at_level {
18230                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18231                        } else if current_level == fold_at_level {
18232                            // Fold iff there is no selection completely contained within the fold region
18233                            if !row_ranges_to_keep.iter().any(|selection| {
18234                                selection.end >= nested_start_row
18235                                    && selection.start <= nested_end_row
18236                            }) {
18237                                to_fold.push(crease);
18238                            }
18239                        }
18240
18241                        start_row = nested_end_row + 1;
18242                    }
18243                    None => start_row += 1,
18244                }
18245            }
18246        }
18247
18248        self.fold_creases(to_fold, true, window, cx);
18249    }
18250
18251    pub fn fold_at_level_1(
18252        &mut self,
18253        _: &actions::FoldAtLevel1,
18254        window: &mut Window,
18255        cx: &mut Context<Self>,
18256    ) {
18257        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18258    }
18259
18260    pub fn fold_at_level_2(
18261        &mut self,
18262        _: &actions::FoldAtLevel2,
18263        window: &mut Window,
18264        cx: &mut Context<Self>,
18265    ) {
18266        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18267    }
18268
18269    pub fn fold_at_level_3(
18270        &mut self,
18271        _: &actions::FoldAtLevel3,
18272        window: &mut Window,
18273        cx: &mut Context<Self>,
18274    ) {
18275        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18276    }
18277
18278    pub fn fold_at_level_4(
18279        &mut self,
18280        _: &actions::FoldAtLevel4,
18281        window: &mut Window,
18282        cx: &mut Context<Self>,
18283    ) {
18284        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18285    }
18286
18287    pub fn fold_at_level_5(
18288        &mut self,
18289        _: &actions::FoldAtLevel5,
18290        window: &mut Window,
18291        cx: &mut Context<Self>,
18292    ) {
18293        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18294    }
18295
18296    pub fn fold_at_level_6(
18297        &mut self,
18298        _: &actions::FoldAtLevel6,
18299        window: &mut Window,
18300        cx: &mut Context<Self>,
18301    ) {
18302        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18303    }
18304
18305    pub fn fold_at_level_7(
18306        &mut self,
18307        _: &actions::FoldAtLevel7,
18308        window: &mut Window,
18309        cx: &mut Context<Self>,
18310    ) {
18311        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18312    }
18313
18314    pub fn fold_at_level_8(
18315        &mut self,
18316        _: &actions::FoldAtLevel8,
18317        window: &mut Window,
18318        cx: &mut Context<Self>,
18319    ) {
18320        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18321    }
18322
18323    pub fn fold_at_level_9(
18324        &mut self,
18325        _: &actions::FoldAtLevel9,
18326        window: &mut Window,
18327        cx: &mut Context<Self>,
18328    ) {
18329        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18330    }
18331
18332    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18333        if self.buffer.read(cx).is_singleton() {
18334            let mut fold_ranges = Vec::new();
18335            let snapshot = self.buffer.read(cx).snapshot(cx);
18336
18337            for row in 0..snapshot.max_row().0 {
18338                if let Some(foldable_range) = self
18339                    .snapshot(window, cx)
18340                    .crease_for_buffer_row(MultiBufferRow(row))
18341                {
18342                    fold_ranges.push(foldable_range);
18343                }
18344            }
18345
18346            self.fold_creases(fold_ranges, true, window, cx);
18347        } else {
18348            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18349                editor
18350                    .update_in(cx, |editor, _, cx| {
18351                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18352                            editor.fold_buffer(buffer_id, cx);
18353                        }
18354                    })
18355                    .ok();
18356            });
18357        }
18358    }
18359
18360    pub fn fold_function_bodies(
18361        &mut self,
18362        _: &actions::FoldFunctionBodies,
18363        window: &mut Window,
18364        cx: &mut Context<Self>,
18365    ) {
18366        let snapshot = self.buffer.read(cx).snapshot(cx);
18367
18368        let ranges = snapshot
18369            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18370            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18371            .collect::<Vec<_>>();
18372
18373        let creases = ranges
18374            .into_iter()
18375            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18376            .collect();
18377
18378        self.fold_creases(creases, true, window, cx);
18379    }
18380
18381    pub fn fold_recursive(
18382        &mut self,
18383        _: &actions::FoldRecursive,
18384        window: &mut Window,
18385        cx: &mut Context<Self>,
18386    ) {
18387        let mut to_fold = Vec::new();
18388        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18389        let selections = self.selections.all_adjusted(cx);
18390
18391        for selection in selections {
18392            let range = selection.range().sorted();
18393            let buffer_start_row = range.start.row;
18394
18395            if range.start.row != range.end.row {
18396                let mut found = false;
18397                for row in range.start.row..=range.end.row {
18398                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18399                        found = true;
18400                        to_fold.push(crease);
18401                    }
18402                }
18403                if found {
18404                    continue;
18405                }
18406            }
18407
18408            for row in (0..=range.start.row).rev() {
18409                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18410                    if crease.range().end.row >= buffer_start_row {
18411                        to_fold.push(crease);
18412                    } else {
18413                        break;
18414                    }
18415                }
18416            }
18417        }
18418
18419        self.fold_creases(to_fold, true, window, cx);
18420    }
18421
18422    pub fn fold_at(
18423        &mut self,
18424        buffer_row: MultiBufferRow,
18425        window: &mut Window,
18426        cx: &mut Context<Self>,
18427    ) {
18428        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18429
18430        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18431            let autoscroll = self
18432                .selections
18433                .all::<Point>(cx)
18434                .iter()
18435                .any(|selection| crease.range().overlaps(&selection.range()));
18436
18437            self.fold_creases(vec![crease], autoscroll, window, cx);
18438        }
18439    }
18440
18441    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18442        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18443            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18444            let buffer = display_map.buffer_snapshot();
18445            let selections = self.selections.all::<Point>(cx);
18446            let ranges = selections
18447                .iter()
18448                .map(|s| {
18449                    let range = s.display_range(&display_map).sorted();
18450                    let mut start = range.start.to_point(&display_map);
18451                    let mut end = range.end.to_point(&display_map);
18452                    start.column = 0;
18453                    end.column = buffer.line_len(MultiBufferRow(end.row));
18454                    start..end
18455                })
18456                .collect::<Vec<_>>();
18457
18458            self.unfold_ranges(&ranges, true, true, cx);
18459        } else {
18460            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18461            let buffer_ids = self
18462                .selections
18463                .disjoint_anchor_ranges()
18464                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18465                .collect::<HashSet<_>>();
18466            for buffer_id in buffer_ids {
18467                self.unfold_buffer(buffer_id, cx);
18468            }
18469        }
18470    }
18471
18472    pub fn unfold_recursive(
18473        &mut self,
18474        _: &UnfoldRecursive,
18475        _window: &mut Window,
18476        cx: &mut Context<Self>,
18477    ) {
18478        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18479        let selections = self.selections.all::<Point>(cx);
18480        let ranges = selections
18481            .iter()
18482            .map(|s| {
18483                let mut range = s.display_range(&display_map).sorted();
18484                *range.start.column_mut() = 0;
18485                *range.end.column_mut() = display_map.line_len(range.end.row());
18486                let start = range.start.to_point(&display_map);
18487                let end = range.end.to_point(&display_map);
18488                start..end
18489            })
18490            .collect::<Vec<_>>();
18491
18492        self.unfold_ranges(&ranges, true, true, cx);
18493    }
18494
18495    pub fn unfold_at(
18496        &mut self,
18497        buffer_row: MultiBufferRow,
18498        _window: &mut Window,
18499        cx: &mut Context<Self>,
18500    ) {
18501        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18502
18503        let intersection_range = Point::new(buffer_row.0, 0)
18504            ..Point::new(
18505                buffer_row.0,
18506                display_map.buffer_snapshot().line_len(buffer_row),
18507            );
18508
18509        let autoscroll = self
18510            .selections
18511            .all::<Point>(cx)
18512            .iter()
18513            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18514
18515        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18516    }
18517
18518    pub fn unfold_all(
18519        &mut self,
18520        _: &actions::UnfoldAll,
18521        _window: &mut Window,
18522        cx: &mut Context<Self>,
18523    ) {
18524        if self.buffer.read(cx).is_singleton() {
18525            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18526            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18527        } else {
18528            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18529                editor
18530                    .update(cx, |editor, cx| {
18531                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18532                            editor.unfold_buffer(buffer_id, cx);
18533                        }
18534                    })
18535                    .ok();
18536            });
18537        }
18538    }
18539
18540    pub fn fold_selected_ranges(
18541        &mut self,
18542        _: &FoldSelectedRanges,
18543        window: &mut Window,
18544        cx: &mut Context<Self>,
18545    ) {
18546        let selections = self.selections.all_adjusted(cx);
18547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18548        let ranges = selections
18549            .into_iter()
18550            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18551            .collect::<Vec<_>>();
18552        self.fold_creases(ranges, true, window, cx);
18553    }
18554
18555    pub fn fold_ranges<T: ToOffset + Clone>(
18556        &mut self,
18557        ranges: Vec<Range<T>>,
18558        auto_scroll: bool,
18559        window: &mut Window,
18560        cx: &mut Context<Self>,
18561    ) {
18562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18563        let ranges = ranges
18564            .into_iter()
18565            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18566            .collect::<Vec<_>>();
18567        self.fold_creases(ranges, auto_scroll, window, cx);
18568    }
18569
18570    pub fn fold_creases<T: ToOffset + Clone>(
18571        &mut self,
18572        creases: Vec<Crease<T>>,
18573        auto_scroll: bool,
18574        _window: &mut Window,
18575        cx: &mut Context<Self>,
18576    ) {
18577        if creases.is_empty() {
18578            return;
18579        }
18580
18581        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18582
18583        if auto_scroll {
18584            self.request_autoscroll(Autoscroll::fit(), cx);
18585        }
18586
18587        cx.notify();
18588
18589        self.scrollbar_marker_state.dirty = true;
18590        self.folds_did_change(cx);
18591    }
18592
18593    /// Removes any folds whose ranges intersect any of the given ranges.
18594    pub fn unfold_ranges<T: ToOffset + Clone>(
18595        &mut self,
18596        ranges: &[Range<T>],
18597        inclusive: bool,
18598        auto_scroll: bool,
18599        cx: &mut Context<Self>,
18600    ) {
18601        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18602            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18603        });
18604        self.folds_did_change(cx);
18605    }
18606
18607    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18608        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18609            return;
18610        }
18611        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18612        self.display_map.update(cx, |display_map, cx| {
18613            display_map.fold_buffers([buffer_id], cx)
18614        });
18615        cx.emit(EditorEvent::BufferFoldToggled {
18616            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18617            folded: true,
18618        });
18619        cx.notify();
18620    }
18621
18622    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18623        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18624            return;
18625        }
18626        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18627        self.display_map.update(cx, |display_map, cx| {
18628            display_map.unfold_buffers([buffer_id], cx);
18629        });
18630        cx.emit(EditorEvent::BufferFoldToggled {
18631            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18632            folded: false,
18633        });
18634        cx.notify();
18635    }
18636
18637    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18638        self.display_map.read(cx).is_buffer_folded(buffer)
18639    }
18640
18641    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18642        self.display_map.read(cx).folded_buffers()
18643    }
18644
18645    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18646        self.display_map.update(cx, |display_map, cx| {
18647            display_map.disable_header_for_buffer(buffer_id, cx);
18648        });
18649        cx.notify();
18650    }
18651
18652    /// Removes any folds with the given ranges.
18653    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18654        &mut self,
18655        ranges: &[Range<T>],
18656        type_id: TypeId,
18657        auto_scroll: bool,
18658        cx: &mut Context<Self>,
18659    ) {
18660        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18661            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18662        });
18663        self.folds_did_change(cx);
18664    }
18665
18666    fn remove_folds_with<T: ToOffset + Clone>(
18667        &mut self,
18668        ranges: &[Range<T>],
18669        auto_scroll: bool,
18670        cx: &mut Context<Self>,
18671        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18672    ) {
18673        if ranges.is_empty() {
18674            return;
18675        }
18676
18677        let mut buffers_affected = HashSet::default();
18678        let multi_buffer = self.buffer().read(cx);
18679        for range in ranges {
18680            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18681                buffers_affected.insert(buffer.read(cx).remote_id());
18682            };
18683        }
18684
18685        self.display_map.update(cx, update);
18686
18687        if auto_scroll {
18688            self.request_autoscroll(Autoscroll::fit(), cx);
18689        }
18690
18691        cx.notify();
18692        self.scrollbar_marker_state.dirty = true;
18693        self.active_indent_guides_state.dirty = true;
18694    }
18695
18696    pub fn update_renderer_widths(
18697        &mut self,
18698        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18699        cx: &mut Context<Self>,
18700    ) -> bool {
18701        self.display_map
18702            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18703    }
18704
18705    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18706        self.display_map.read(cx).fold_placeholder.clone()
18707    }
18708
18709    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18710        self.buffer.update(cx, |buffer, cx| {
18711            buffer.set_all_diff_hunks_expanded(cx);
18712        });
18713    }
18714
18715    pub fn expand_all_diff_hunks(
18716        &mut self,
18717        _: &ExpandAllDiffHunks,
18718        _window: &mut Window,
18719        cx: &mut Context<Self>,
18720    ) {
18721        self.buffer.update(cx, |buffer, cx| {
18722            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18723        });
18724    }
18725
18726    pub fn toggle_selected_diff_hunks(
18727        &mut self,
18728        _: &ToggleSelectedDiffHunks,
18729        _window: &mut Window,
18730        cx: &mut Context<Self>,
18731    ) {
18732        let ranges: Vec<_> = self
18733            .selections
18734            .disjoint_anchors()
18735            .iter()
18736            .map(|s| s.range())
18737            .collect();
18738        self.toggle_diff_hunks_in_ranges(ranges, cx);
18739    }
18740
18741    pub fn diff_hunks_in_ranges<'a>(
18742        &'a self,
18743        ranges: &'a [Range<Anchor>],
18744        buffer: &'a MultiBufferSnapshot,
18745    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18746        ranges.iter().flat_map(move |range| {
18747            let end_excerpt_id = range.end.excerpt_id;
18748            let range = range.to_point(buffer);
18749            let mut peek_end = range.end;
18750            if range.end.row < buffer.max_row().0 {
18751                peek_end = Point::new(range.end.row + 1, 0);
18752            }
18753            buffer
18754                .diff_hunks_in_range(range.start..peek_end)
18755                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18756        })
18757    }
18758
18759    pub fn has_stageable_diff_hunks_in_ranges(
18760        &self,
18761        ranges: &[Range<Anchor>],
18762        snapshot: &MultiBufferSnapshot,
18763    ) -> bool {
18764        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18765        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18766    }
18767
18768    pub fn toggle_staged_selected_diff_hunks(
18769        &mut self,
18770        _: &::git::ToggleStaged,
18771        _: &mut Window,
18772        cx: &mut Context<Self>,
18773    ) {
18774        let snapshot = self.buffer.read(cx).snapshot(cx);
18775        let ranges: Vec<_> = self
18776            .selections
18777            .disjoint_anchors()
18778            .iter()
18779            .map(|s| s.range())
18780            .collect();
18781        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18782        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18783    }
18784
18785    pub fn set_render_diff_hunk_controls(
18786        &mut self,
18787        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18788        cx: &mut Context<Self>,
18789    ) {
18790        self.render_diff_hunk_controls = render_diff_hunk_controls;
18791        cx.notify();
18792    }
18793
18794    pub fn stage_and_next(
18795        &mut self,
18796        _: &::git::StageAndNext,
18797        window: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        self.do_stage_or_unstage_and_next(true, window, cx);
18801    }
18802
18803    pub fn unstage_and_next(
18804        &mut self,
18805        _: &::git::UnstageAndNext,
18806        window: &mut Window,
18807        cx: &mut Context<Self>,
18808    ) {
18809        self.do_stage_or_unstage_and_next(false, window, cx);
18810    }
18811
18812    pub fn stage_or_unstage_diff_hunks(
18813        &mut self,
18814        stage: bool,
18815        ranges: Vec<Range<Anchor>>,
18816        cx: &mut Context<Self>,
18817    ) {
18818        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18819        cx.spawn(async move |this, cx| {
18820            task.await?;
18821            this.update(cx, |this, cx| {
18822                let snapshot = this.buffer.read(cx).snapshot(cx);
18823                let chunk_by = this
18824                    .diff_hunks_in_ranges(&ranges, &snapshot)
18825                    .chunk_by(|hunk| hunk.buffer_id);
18826                for (buffer_id, hunks) in &chunk_by {
18827                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18828                }
18829            })
18830        })
18831        .detach_and_log_err(cx);
18832    }
18833
18834    fn save_buffers_for_ranges_if_needed(
18835        &mut self,
18836        ranges: &[Range<Anchor>],
18837        cx: &mut Context<Editor>,
18838    ) -> Task<Result<()>> {
18839        let multibuffer = self.buffer.read(cx);
18840        let snapshot = multibuffer.read(cx);
18841        let buffer_ids: HashSet<_> = ranges
18842            .iter()
18843            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18844            .collect();
18845        drop(snapshot);
18846
18847        let mut buffers = HashSet::default();
18848        for buffer_id in buffer_ids {
18849            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18850                let buffer = buffer_entity.read(cx);
18851                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18852                {
18853                    buffers.insert(buffer_entity);
18854                }
18855            }
18856        }
18857
18858        if let Some(project) = &self.project {
18859            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18860        } else {
18861            Task::ready(Ok(()))
18862        }
18863    }
18864
18865    fn do_stage_or_unstage_and_next(
18866        &mut self,
18867        stage: bool,
18868        window: &mut Window,
18869        cx: &mut Context<Self>,
18870    ) {
18871        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18872
18873        if ranges.iter().any(|range| range.start != range.end) {
18874            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18875            return;
18876        }
18877
18878        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18879        let snapshot = self.snapshot(window, cx);
18880        let position = self.selections.newest::<Point>(cx).head();
18881        let mut row = snapshot
18882            .buffer_snapshot()
18883            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18884            .find(|hunk| hunk.row_range.start.0 > position.row)
18885            .map(|hunk| hunk.row_range.start);
18886
18887        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18888        // Outside of the project diff editor, wrap around to the beginning.
18889        if !all_diff_hunks_expanded {
18890            row = row.or_else(|| {
18891                snapshot
18892                    .buffer_snapshot()
18893                    .diff_hunks_in_range(Point::zero()..position)
18894                    .find(|hunk| hunk.row_range.end.0 < position.row)
18895                    .map(|hunk| hunk.row_range.start)
18896            });
18897        }
18898
18899        if let Some(row) = row {
18900            let destination = Point::new(row.0, 0);
18901            let autoscroll = Autoscroll::center();
18902
18903            self.unfold_ranges(&[destination..destination], false, false, cx);
18904            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18905                s.select_ranges([destination..destination]);
18906            });
18907        }
18908    }
18909
18910    fn do_stage_or_unstage(
18911        &self,
18912        stage: bool,
18913        buffer_id: BufferId,
18914        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18915        cx: &mut App,
18916    ) -> Option<()> {
18917        let project = self.project()?;
18918        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18919        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18920        let buffer_snapshot = buffer.read(cx).snapshot();
18921        let file_exists = buffer_snapshot
18922            .file()
18923            .is_some_and(|file| file.disk_state().exists());
18924        diff.update(cx, |diff, cx| {
18925            diff.stage_or_unstage_hunks(
18926                stage,
18927                &hunks
18928                    .map(|hunk| buffer_diff::DiffHunk {
18929                        buffer_range: hunk.buffer_range,
18930                        diff_base_byte_range: hunk.diff_base_byte_range,
18931                        secondary_status: hunk.secondary_status,
18932                        range: Point::zero()..Point::zero(), // unused
18933                    })
18934                    .collect::<Vec<_>>(),
18935                &buffer_snapshot,
18936                file_exists,
18937                cx,
18938            )
18939        });
18940        None
18941    }
18942
18943    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18944        let ranges: Vec<_> = self
18945            .selections
18946            .disjoint_anchors()
18947            .iter()
18948            .map(|s| s.range())
18949            .collect();
18950        self.buffer
18951            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18952    }
18953
18954    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18955        self.buffer.update(cx, |buffer, cx| {
18956            let ranges = vec![Anchor::min()..Anchor::max()];
18957            if !buffer.all_diff_hunks_expanded()
18958                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18959            {
18960                buffer.collapse_diff_hunks(ranges, cx);
18961                true
18962            } else {
18963                false
18964            }
18965        })
18966    }
18967
18968    fn toggle_diff_hunks_in_ranges(
18969        &mut self,
18970        ranges: Vec<Range<Anchor>>,
18971        cx: &mut Context<Editor>,
18972    ) {
18973        self.buffer.update(cx, |buffer, cx| {
18974            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18975            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18976        })
18977    }
18978
18979    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18980        self.buffer.update(cx, |buffer, cx| {
18981            let snapshot = buffer.snapshot(cx);
18982            let excerpt_id = range.end.excerpt_id;
18983            let point_range = range.to_point(&snapshot);
18984            let expand = !buffer.single_hunk_is_expanded(range, cx);
18985            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18986        })
18987    }
18988
18989    pub(crate) fn apply_all_diff_hunks(
18990        &mut self,
18991        _: &ApplyAllDiffHunks,
18992        window: &mut Window,
18993        cx: &mut Context<Self>,
18994    ) {
18995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18996
18997        let buffers = self.buffer.read(cx).all_buffers();
18998        for branch_buffer in buffers {
18999            branch_buffer.update(cx, |branch_buffer, cx| {
19000                branch_buffer.merge_into_base(Vec::new(), cx);
19001            });
19002        }
19003
19004        if let Some(project) = self.project.clone() {
19005            self.save(
19006                SaveOptions {
19007                    format: true,
19008                    autosave: false,
19009                },
19010                project,
19011                window,
19012                cx,
19013            )
19014            .detach_and_log_err(cx);
19015        }
19016    }
19017
19018    pub(crate) fn apply_selected_diff_hunks(
19019        &mut self,
19020        _: &ApplyDiffHunk,
19021        window: &mut Window,
19022        cx: &mut Context<Self>,
19023    ) {
19024        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19025        let snapshot = self.snapshot(window, cx);
19026        let hunks = snapshot.hunks_for_ranges(
19027            self.selections
19028                .all(cx)
19029                .into_iter()
19030                .map(|selection| selection.range()),
19031        );
19032        let mut ranges_by_buffer = HashMap::default();
19033        self.transact(window, cx, |editor, _window, cx| {
19034            for hunk in hunks {
19035                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19036                    ranges_by_buffer
19037                        .entry(buffer.clone())
19038                        .or_insert_with(Vec::new)
19039                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19040                }
19041            }
19042
19043            for (buffer, ranges) in ranges_by_buffer {
19044                buffer.update(cx, |buffer, cx| {
19045                    buffer.merge_into_base(ranges, cx);
19046                });
19047            }
19048        });
19049
19050        if let Some(project) = self.project.clone() {
19051            self.save(
19052                SaveOptions {
19053                    format: true,
19054                    autosave: false,
19055                },
19056                project,
19057                window,
19058                cx,
19059            )
19060            .detach_and_log_err(cx);
19061        }
19062    }
19063
19064    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19065        if hovered != self.gutter_hovered {
19066            self.gutter_hovered = hovered;
19067            cx.notify();
19068        }
19069    }
19070
19071    pub fn insert_blocks(
19072        &mut self,
19073        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19074        autoscroll: Option<Autoscroll>,
19075        cx: &mut Context<Self>,
19076    ) -> Vec<CustomBlockId> {
19077        let blocks = self
19078            .display_map
19079            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19080        if let Some(autoscroll) = autoscroll {
19081            self.request_autoscroll(autoscroll, cx);
19082        }
19083        cx.notify();
19084        blocks
19085    }
19086
19087    pub fn resize_blocks(
19088        &mut self,
19089        heights: HashMap<CustomBlockId, u32>,
19090        autoscroll: Option<Autoscroll>,
19091        cx: &mut Context<Self>,
19092    ) {
19093        self.display_map
19094            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19095        if let Some(autoscroll) = autoscroll {
19096            self.request_autoscroll(autoscroll, cx);
19097        }
19098        cx.notify();
19099    }
19100
19101    pub fn replace_blocks(
19102        &mut self,
19103        renderers: HashMap<CustomBlockId, RenderBlock>,
19104        autoscroll: Option<Autoscroll>,
19105        cx: &mut Context<Self>,
19106    ) {
19107        self.display_map
19108            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19109        if let Some(autoscroll) = autoscroll {
19110            self.request_autoscroll(autoscroll, cx);
19111        }
19112        cx.notify();
19113    }
19114
19115    pub fn remove_blocks(
19116        &mut self,
19117        block_ids: HashSet<CustomBlockId>,
19118        autoscroll: Option<Autoscroll>,
19119        cx: &mut Context<Self>,
19120    ) {
19121        self.display_map.update(cx, |display_map, cx| {
19122            display_map.remove_blocks(block_ids, cx)
19123        });
19124        if let Some(autoscroll) = autoscroll {
19125            self.request_autoscroll(autoscroll, cx);
19126        }
19127        cx.notify();
19128    }
19129
19130    pub fn row_for_block(
19131        &self,
19132        block_id: CustomBlockId,
19133        cx: &mut Context<Self>,
19134    ) -> Option<DisplayRow> {
19135        self.display_map
19136            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19137    }
19138
19139    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19140        self.focused_block = Some(focused_block);
19141    }
19142
19143    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19144        self.focused_block.take()
19145    }
19146
19147    pub fn insert_creases(
19148        &mut self,
19149        creases: impl IntoIterator<Item = Crease<Anchor>>,
19150        cx: &mut Context<Self>,
19151    ) -> Vec<CreaseId> {
19152        self.display_map
19153            .update(cx, |map, cx| map.insert_creases(creases, cx))
19154    }
19155
19156    pub fn remove_creases(
19157        &mut self,
19158        ids: impl IntoIterator<Item = CreaseId>,
19159        cx: &mut Context<Self>,
19160    ) -> Vec<(CreaseId, Range<Anchor>)> {
19161        self.display_map
19162            .update(cx, |map, cx| map.remove_creases(ids, cx))
19163    }
19164
19165    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19166        self.display_map
19167            .update(cx, |map, cx| map.snapshot(cx))
19168            .longest_row()
19169    }
19170
19171    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19172        self.display_map
19173            .update(cx, |map, cx| map.snapshot(cx))
19174            .max_point()
19175    }
19176
19177    pub fn text(&self, cx: &App) -> String {
19178        self.buffer.read(cx).read(cx).text()
19179    }
19180
19181    pub fn is_empty(&self, cx: &App) -> bool {
19182        self.buffer.read(cx).read(cx).is_empty()
19183    }
19184
19185    pub fn text_option(&self, cx: &App) -> Option<String> {
19186        let text = self.text(cx);
19187        let text = text.trim();
19188
19189        if text.is_empty() {
19190            return None;
19191        }
19192
19193        Some(text.to_string())
19194    }
19195
19196    pub fn set_text(
19197        &mut self,
19198        text: impl Into<Arc<str>>,
19199        window: &mut Window,
19200        cx: &mut Context<Self>,
19201    ) {
19202        self.transact(window, cx, |this, _, cx| {
19203            this.buffer
19204                .read(cx)
19205                .as_singleton()
19206                .expect("you can only call set_text on editors for singleton buffers")
19207                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19208        });
19209    }
19210
19211    pub fn display_text(&self, cx: &mut App) -> String {
19212        self.display_map
19213            .update(cx, |map, cx| map.snapshot(cx))
19214            .text()
19215    }
19216
19217    fn create_minimap(
19218        &self,
19219        minimap_settings: MinimapSettings,
19220        window: &mut Window,
19221        cx: &mut Context<Self>,
19222    ) -> Option<Entity<Self>> {
19223        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19224            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19225    }
19226
19227    fn initialize_new_minimap(
19228        &self,
19229        minimap_settings: MinimapSettings,
19230        window: &mut Window,
19231        cx: &mut Context<Self>,
19232    ) -> Entity<Self> {
19233        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19234
19235        let mut minimap = Editor::new_internal(
19236            EditorMode::Minimap {
19237                parent: cx.weak_entity(),
19238            },
19239            self.buffer.clone(),
19240            None,
19241            Some(self.display_map.clone()),
19242            window,
19243            cx,
19244        );
19245        minimap.scroll_manager.clone_state(&self.scroll_manager);
19246        minimap.set_text_style_refinement(TextStyleRefinement {
19247            font_size: Some(MINIMAP_FONT_SIZE),
19248            font_weight: Some(MINIMAP_FONT_WEIGHT),
19249            ..Default::default()
19250        });
19251        minimap.update_minimap_configuration(minimap_settings, cx);
19252        cx.new(|_| minimap)
19253    }
19254
19255    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19256        let current_line_highlight = minimap_settings
19257            .current_line_highlight
19258            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19259        self.set_current_line_highlight(Some(current_line_highlight));
19260    }
19261
19262    pub fn minimap(&self) -> Option<&Entity<Self>> {
19263        self.minimap
19264            .as_ref()
19265            .filter(|_| self.minimap_visibility.visible())
19266    }
19267
19268    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19269        let mut wrap_guides = smallvec![];
19270
19271        if self.show_wrap_guides == Some(false) {
19272            return wrap_guides;
19273        }
19274
19275        let settings = self.buffer.read(cx).language_settings(cx);
19276        if settings.show_wrap_guides {
19277            match self.soft_wrap_mode(cx) {
19278                SoftWrap::Column(soft_wrap) => {
19279                    wrap_guides.push((soft_wrap as usize, true));
19280                }
19281                SoftWrap::Bounded(soft_wrap) => {
19282                    wrap_guides.push((soft_wrap as usize, true));
19283                }
19284                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19285            }
19286            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19287        }
19288
19289        wrap_guides
19290    }
19291
19292    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19293        let settings = self.buffer.read(cx).language_settings(cx);
19294        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19295        match mode {
19296            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19297                SoftWrap::None
19298            }
19299            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19300            language_settings::SoftWrap::PreferredLineLength => {
19301                SoftWrap::Column(settings.preferred_line_length)
19302            }
19303            language_settings::SoftWrap::Bounded => {
19304                SoftWrap::Bounded(settings.preferred_line_length)
19305            }
19306        }
19307    }
19308
19309    pub fn set_soft_wrap_mode(
19310        &mut self,
19311        mode: language_settings::SoftWrap,
19312
19313        cx: &mut Context<Self>,
19314    ) {
19315        self.soft_wrap_mode_override = Some(mode);
19316        cx.notify();
19317    }
19318
19319    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19320        self.hard_wrap = hard_wrap;
19321        cx.notify();
19322    }
19323
19324    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19325        self.text_style_refinement = Some(style);
19326    }
19327
19328    /// called by the Element so we know what style we were most recently rendered with.
19329    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19330        // We intentionally do not inform the display map about the minimap style
19331        // so that wrapping is not recalculated and stays consistent for the editor
19332        // and its linked minimap.
19333        if !self.mode.is_minimap() {
19334            let font = style.text.font();
19335            let font_size = style.text.font_size.to_pixels(window.rem_size());
19336            let display_map = self
19337                .placeholder_display_map
19338                .as_ref()
19339                .filter(|_| self.is_empty(cx))
19340                .unwrap_or(&self.display_map);
19341
19342            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19343        }
19344        self.style = Some(style);
19345    }
19346
19347    pub fn style(&self) -> Option<&EditorStyle> {
19348        self.style.as_ref()
19349    }
19350
19351    // Called by the element. This method is not designed to be called outside of the editor
19352    // element's layout code because it does not notify when rewrapping is computed synchronously.
19353    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19354        if self.is_empty(cx) {
19355            self.placeholder_display_map
19356                .as_ref()
19357                .map_or(false, |display_map| {
19358                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19359                })
19360        } else {
19361            self.display_map
19362                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19363        }
19364    }
19365
19366    pub fn set_soft_wrap(&mut self) {
19367        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19368    }
19369
19370    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19371        if self.soft_wrap_mode_override.is_some() {
19372            self.soft_wrap_mode_override.take();
19373        } else {
19374            let soft_wrap = match self.soft_wrap_mode(cx) {
19375                SoftWrap::GitDiff => return,
19376                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19377                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19378                    language_settings::SoftWrap::None
19379                }
19380            };
19381            self.soft_wrap_mode_override = Some(soft_wrap);
19382        }
19383        cx.notify();
19384    }
19385
19386    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19387        let Some(workspace) = self.workspace() else {
19388            return;
19389        };
19390        let fs = workspace.read(cx).app_state().fs.clone();
19391        let current_show = TabBarSettings::get_global(cx).show;
19392        update_settings_file(fs, cx, move |setting, _| {
19393            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19394        });
19395    }
19396
19397    pub fn toggle_indent_guides(
19398        &mut self,
19399        _: &ToggleIndentGuides,
19400        _: &mut Window,
19401        cx: &mut Context<Self>,
19402    ) {
19403        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19404            self.buffer
19405                .read(cx)
19406                .language_settings(cx)
19407                .indent_guides
19408                .enabled
19409        });
19410        self.show_indent_guides = Some(!currently_enabled);
19411        cx.notify();
19412    }
19413
19414    fn should_show_indent_guides(&self) -> Option<bool> {
19415        self.show_indent_guides
19416    }
19417
19418    pub fn toggle_line_numbers(
19419        &mut self,
19420        _: &ToggleLineNumbers,
19421        _: &mut Window,
19422        cx: &mut Context<Self>,
19423    ) {
19424        let mut editor_settings = EditorSettings::get_global(cx).clone();
19425        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19426        EditorSettings::override_global(editor_settings, cx);
19427    }
19428
19429    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19430        if let Some(show_line_numbers) = self.show_line_numbers {
19431            return show_line_numbers;
19432        }
19433        EditorSettings::get_global(cx).gutter.line_numbers
19434    }
19435
19436    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19437        self.use_relative_line_numbers
19438            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19439    }
19440
19441    pub fn toggle_relative_line_numbers(
19442        &mut self,
19443        _: &ToggleRelativeLineNumbers,
19444        _: &mut Window,
19445        cx: &mut Context<Self>,
19446    ) {
19447        let is_relative = self.should_use_relative_line_numbers(cx);
19448        self.set_relative_line_number(Some(!is_relative), cx)
19449    }
19450
19451    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19452        self.use_relative_line_numbers = is_relative;
19453        cx.notify();
19454    }
19455
19456    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19457        self.show_gutter = show_gutter;
19458        cx.notify();
19459    }
19460
19461    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19462        self.show_scrollbars = ScrollbarAxes {
19463            horizontal: show,
19464            vertical: show,
19465        };
19466        cx.notify();
19467    }
19468
19469    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19470        self.show_scrollbars.vertical = show;
19471        cx.notify();
19472    }
19473
19474    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19475        self.show_scrollbars.horizontal = show;
19476        cx.notify();
19477    }
19478
19479    pub fn set_minimap_visibility(
19480        &mut self,
19481        minimap_visibility: MinimapVisibility,
19482        window: &mut Window,
19483        cx: &mut Context<Self>,
19484    ) {
19485        if self.minimap_visibility != minimap_visibility {
19486            if minimap_visibility.visible() && self.minimap.is_none() {
19487                let minimap_settings = EditorSettings::get_global(cx).minimap;
19488                self.minimap =
19489                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19490            }
19491            self.minimap_visibility = minimap_visibility;
19492            cx.notify();
19493        }
19494    }
19495
19496    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19497        self.set_show_scrollbars(false, cx);
19498        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19499    }
19500
19501    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19502        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19503    }
19504
19505    /// Normally the text in full mode and auto height editors is padded on the
19506    /// left side by roughly half a character width for improved hit testing.
19507    ///
19508    /// Use this method to disable this for cases where this is not wanted (e.g.
19509    /// if you want to align the editor text with some other text above or below)
19510    /// or if you want to add this padding to single-line editors.
19511    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19512        self.offset_content = offset_content;
19513        cx.notify();
19514    }
19515
19516    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19517        self.show_line_numbers = Some(show_line_numbers);
19518        cx.notify();
19519    }
19520
19521    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19522        self.disable_expand_excerpt_buttons = true;
19523        cx.notify();
19524    }
19525
19526    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19527        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19528        cx.notify();
19529    }
19530
19531    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19532        self.show_code_actions = Some(show_code_actions);
19533        cx.notify();
19534    }
19535
19536    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19537        self.show_runnables = Some(show_runnables);
19538        cx.notify();
19539    }
19540
19541    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19542        self.show_breakpoints = Some(show_breakpoints);
19543        cx.notify();
19544    }
19545
19546    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19547        if self.display_map.read(cx).masked != masked {
19548            self.display_map.update(cx, |map, _| map.masked = masked);
19549        }
19550        cx.notify()
19551    }
19552
19553    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19554        self.show_wrap_guides = Some(show_wrap_guides);
19555        cx.notify();
19556    }
19557
19558    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19559        self.show_indent_guides = Some(show_indent_guides);
19560        cx.notify();
19561    }
19562
19563    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19564        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19565            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19566                && let Some(dir) = file.abs_path(cx).parent()
19567            {
19568                return Some(dir.to_owned());
19569            }
19570        }
19571
19572        None
19573    }
19574
19575    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19576        self.active_excerpt(cx)?
19577            .1
19578            .read(cx)
19579            .file()
19580            .and_then(|f| f.as_local())
19581    }
19582
19583    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19584        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19585            let buffer = buffer.read(cx);
19586            if let Some(project_path) = buffer.project_path(cx) {
19587                let project = self.project()?.read(cx);
19588                project.absolute_path(&project_path, cx)
19589            } else {
19590                buffer
19591                    .file()
19592                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19593            }
19594        })
19595    }
19596
19597    pub fn reveal_in_finder(
19598        &mut self,
19599        _: &RevealInFileManager,
19600        _window: &mut Window,
19601        cx: &mut Context<Self>,
19602    ) {
19603        if let Some(target) = self.target_file(cx) {
19604            cx.reveal_path(&target.abs_path(cx));
19605        }
19606    }
19607
19608    pub fn copy_path(
19609        &mut self,
19610        _: &zed_actions::workspace::CopyPath,
19611        _window: &mut Window,
19612        cx: &mut Context<Self>,
19613    ) {
19614        if let Some(path) = self.target_file_abs_path(cx)
19615            && let Some(path) = path.to_str()
19616        {
19617            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19618        } else {
19619            cx.propagate();
19620        }
19621    }
19622
19623    pub fn copy_relative_path(
19624        &mut self,
19625        _: &zed_actions::workspace::CopyRelativePath,
19626        _window: &mut Window,
19627        cx: &mut Context<Self>,
19628    ) {
19629        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19630            let project = self.project()?.read(cx);
19631            let path = buffer.read(cx).file()?.path();
19632            let path = path.display(project.path_style(cx));
19633            Some(path)
19634        }) {
19635            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19636        } else {
19637            cx.propagate();
19638        }
19639    }
19640
19641    /// Returns the project path for the editor's buffer, if any buffer is
19642    /// opened in the editor.
19643    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19644        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19645            buffer.read(cx).project_path(cx)
19646        } else {
19647            None
19648        }
19649    }
19650
19651    // Returns true if the editor handled a go-to-line request
19652    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19653        maybe!({
19654            let breakpoint_store = self.breakpoint_store.as_ref()?;
19655
19656            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19657            else {
19658                self.clear_row_highlights::<ActiveDebugLine>();
19659                return None;
19660            };
19661
19662            let position = active_stack_frame.position;
19663            let buffer_id = position.buffer_id?;
19664            let snapshot = self
19665                .project
19666                .as_ref()?
19667                .read(cx)
19668                .buffer_for_id(buffer_id, cx)?
19669                .read(cx)
19670                .snapshot();
19671
19672            let mut handled = false;
19673            for (id, ExcerptRange { context, .. }) in
19674                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19675            {
19676                if context.start.cmp(&position, &snapshot).is_ge()
19677                    || context.end.cmp(&position, &snapshot).is_lt()
19678                {
19679                    continue;
19680                }
19681                let snapshot = self.buffer.read(cx).snapshot(cx);
19682                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19683
19684                handled = true;
19685                self.clear_row_highlights::<ActiveDebugLine>();
19686
19687                self.go_to_line::<ActiveDebugLine>(
19688                    multibuffer_anchor,
19689                    Some(cx.theme().colors().editor_debugger_active_line_background),
19690                    window,
19691                    cx,
19692                );
19693
19694                cx.notify();
19695            }
19696
19697            handled.then_some(())
19698        })
19699        .is_some()
19700    }
19701
19702    pub fn copy_file_name_without_extension(
19703        &mut self,
19704        _: &CopyFileNameWithoutExtension,
19705        _: &mut Window,
19706        cx: &mut Context<Self>,
19707    ) {
19708        if let Some(file) = self.target_file(cx)
19709            && let Some(file_stem) = file.path().file_stem()
19710        {
19711            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19712        }
19713    }
19714
19715    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19716        if let Some(file) = self.target_file(cx)
19717            && let Some(name) = file.path().file_name()
19718        {
19719            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19720        }
19721    }
19722
19723    pub fn toggle_git_blame(
19724        &mut self,
19725        _: &::git::Blame,
19726        window: &mut Window,
19727        cx: &mut Context<Self>,
19728    ) {
19729        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19730
19731        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19732            self.start_git_blame(true, window, cx);
19733        }
19734
19735        cx.notify();
19736    }
19737
19738    pub fn toggle_git_blame_inline(
19739        &mut self,
19740        _: &ToggleGitBlameInline,
19741        window: &mut Window,
19742        cx: &mut Context<Self>,
19743    ) {
19744        self.toggle_git_blame_inline_internal(true, window, cx);
19745        cx.notify();
19746    }
19747
19748    pub fn open_git_blame_commit(
19749        &mut self,
19750        _: &OpenGitBlameCommit,
19751        window: &mut Window,
19752        cx: &mut Context<Self>,
19753    ) {
19754        self.open_git_blame_commit_internal(window, cx);
19755    }
19756
19757    fn open_git_blame_commit_internal(
19758        &mut self,
19759        window: &mut Window,
19760        cx: &mut Context<Self>,
19761    ) -> Option<()> {
19762        let blame = self.blame.as_ref()?;
19763        let snapshot = self.snapshot(window, cx);
19764        let cursor = self.selections.newest::<Point>(cx).head();
19765        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19766        let (_, blame_entry) = blame
19767            .update(cx, |blame, cx| {
19768                blame
19769                    .blame_for_rows(
19770                        &[RowInfo {
19771                            buffer_id: Some(buffer.remote_id()),
19772                            buffer_row: Some(point.row),
19773                            ..Default::default()
19774                        }],
19775                        cx,
19776                    )
19777                    .next()
19778            })
19779            .flatten()?;
19780        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19781        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19782        let workspace = self.workspace()?.downgrade();
19783        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19784        None
19785    }
19786
19787    pub fn git_blame_inline_enabled(&self) -> bool {
19788        self.git_blame_inline_enabled
19789    }
19790
19791    pub fn toggle_selection_menu(
19792        &mut self,
19793        _: &ToggleSelectionMenu,
19794        _: &mut Window,
19795        cx: &mut Context<Self>,
19796    ) {
19797        self.show_selection_menu = self
19798            .show_selection_menu
19799            .map(|show_selections_menu| !show_selections_menu)
19800            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19801
19802        cx.notify();
19803    }
19804
19805    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19806        self.show_selection_menu
19807            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19808    }
19809
19810    fn start_git_blame(
19811        &mut self,
19812        user_triggered: bool,
19813        window: &mut Window,
19814        cx: &mut Context<Self>,
19815    ) {
19816        if let Some(project) = self.project() {
19817            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19818                && buffer.read(cx).file().is_none()
19819            {
19820                return;
19821            }
19822
19823            let focused = self.focus_handle(cx).contains_focused(window, cx);
19824
19825            let project = project.clone();
19826            let blame = cx
19827                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19828            self.blame_subscription =
19829                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19830            self.blame = Some(blame);
19831        }
19832    }
19833
19834    fn toggle_git_blame_inline_internal(
19835        &mut self,
19836        user_triggered: bool,
19837        window: &mut Window,
19838        cx: &mut Context<Self>,
19839    ) {
19840        if self.git_blame_inline_enabled {
19841            self.git_blame_inline_enabled = false;
19842            self.show_git_blame_inline = false;
19843            self.show_git_blame_inline_delay_task.take();
19844        } else {
19845            self.git_blame_inline_enabled = true;
19846            self.start_git_blame_inline(user_triggered, window, cx);
19847        }
19848
19849        cx.notify();
19850    }
19851
19852    fn start_git_blame_inline(
19853        &mut self,
19854        user_triggered: bool,
19855        window: &mut Window,
19856        cx: &mut Context<Self>,
19857    ) {
19858        self.start_git_blame(user_triggered, window, cx);
19859
19860        if ProjectSettings::get_global(cx)
19861            .git
19862            .inline_blame_delay()
19863            .is_some()
19864        {
19865            self.start_inline_blame_timer(window, cx);
19866        } else {
19867            self.show_git_blame_inline = true
19868        }
19869    }
19870
19871    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19872        self.blame.as_ref()
19873    }
19874
19875    pub fn show_git_blame_gutter(&self) -> bool {
19876        self.show_git_blame_gutter
19877    }
19878
19879    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19880        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19881    }
19882
19883    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19884        self.show_git_blame_inline
19885            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19886            && !self.newest_selection_head_on_empty_line(cx)
19887            && self.has_blame_entries(cx)
19888    }
19889
19890    fn has_blame_entries(&self, cx: &App) -> bool {
19891        self.blame()
19892            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19893    }
19894
19895    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19896        let cursor_anchor = self.selections.newest_anchor().head();
19897
19898        let snapshot = self.buffer.read(cx).snapshot(cx);
19899        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19900
19901        snapshot.line_len(buffer_row) == 0
19902    }
19903
19904    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19905        let buffer_and_selection = maybe!({
19906            let selection = self.selections.newest::<Point>(cx);
19907            let selection_range = selection.range();
19908
19909            let multi_buffer = self.buffer().read(cx);
19910            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19911            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19912
19913            let (buffer, range, _) = if selection.reversed {
19914                buffer_ranges.first()
19915            } else {
19916                buffer_ranges.last()
19917            }?;
19918
19919            let selection = text::ToPoint::to_point(&range.start, buffer).row
19920                ..text::ToPoint::to_point(&range.end, buffer).row;
19921            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19922        });
19923
19924        let Some((buffer, selection)) = buffer_and_selection else {
19925            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19926        };
19927
19928        let Some(project) = self.project() else {
19929            return Task::ready(Err(anyhow!("editor does not have project")));
19930        };
19931
19932        project.update(cx, |project, cx| {
19933            project.get_permalink_to_line(&buffer, selection, cx)
19934        })
19935    }
19936
19937    pub fn copy_permalink_to_line(
19938        &mut self,
19939        _: &CopyPermalinkToLine,
19940        window: &mut Window,
19941        cx: &mut Context<Self>,
19942    ) {
19943        let permalink_task = self.get_permalink_to_line(cx);
19944        let workspace = self.workspace();
19945
19946        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19947            Ok(permalink) => {
19948                cx.update(|_, cx| {
19949                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19950                })
19951                .ok();
19952            }
19953            Err(err) => {
19954                let message = format!("Failed to copy permalink: {err}");
19955
19956                anyhow::Result::<()>::Err(err).log_err();
19957
19958                if let Some(workspace) = workspace {
19959                    workspace
19960                        .update_in(cx, |workspace, _, cx| {
19961                            struct CopyPermalinkToLine;
19962
19963                            workspace.show_toast(
19964                                Toast::new(
19965                                    NotificationId::unique::<CopyPermalinkToLine>(),
19966                                    message,
19967                                ),
19968                                cx,
19969                            )
19970                        })
19971                        .ok();
19972                }
19973            }
19974        })
19975        .detach();
19976    }
19977
19978    pub fn copy_file_location(
19979        &mut self,
19980        _: &CopyFileLocation,
19981        _: &mut Window,
19982        cx: &mut Context<Self>,
19983    ) {
19984        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19985        if let Some(file) = self.target_file(cx) {
19986            let path = file.path().display(file.path_style(cx));
19987            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19988        }
19989    }
19990
19991    pub fn open_permalink_to_line(
19992        &mut self,
19993        _: &OpenPermalinkToLine,
19994        window: &mut Window,
19995        cx: &mut Context<Self>,
19996    ) {
19997        let permalink_task = self.get_permalink_to_line(cx);
19998        let workspace = self.workspace();
19999
20000        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20001            Ok(permalink) => {
20002                cx.update(|_, cx| {
20003                    cx.open_url(permalink.as_ref());
20004                })
20005                .ok();
20006            }
20007            Err(err) => {
20008                let message = format!("Failed to open permalink: {err}");
20009
20010                anyhow::Result::<()>::Err(err).log_err();
20011
20012                if let Some(workspace) = workspace {
20013                    workspace
20014                        .update(cx, |workspace, cx| {
20015                            struct OpenPermalinkToLine;
20016
20017                            workspace.show_toast(
20018                                Toast::new(
20019                                    NotificationId::unique::<OpenPermalinkToLine>(),
20020                                    message,
20021                                ),
20022                                cx,
20023                            )
20024                        })
20025                        .ok();
20026                }
20027            }
20028        })
20029        .detach();
20030    }
20031
20032    pub fn insert_uuid_v4(
20033        &mut self,
20034        _: &InsertUuidV4,
20035        window: &mut Window,
20036        cx: &mut Context<Self>,
20037    ) {
20038        self.insert_uuid(UuidVersion::V4, window, cx);
20039    }
20040
20041    pub fn insert_uuid_v7(
20042        &mut self,
20043        _: &InsertUuidV7,
20044        window: &mut Window,
20045        cx: &mut Context<Self>,
20046    ) {
20047        self.insert_uuid(UuidVersion::V7, window, cx);
20048    }
20049
20050    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20052        self.transact(window, cx, |this, window, cx| {
20053            let edits = this
20054                .selections
20055                .all::<Point>(cx)
20056                .into_iter()
20057                .map(|selection| {
20058                    let uuid = match version {
20059                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20060                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20061                    };
20062
20063                    (selection.range(), uuid.to_string())
20064                });
20065            this.edit(edits, cx);
20066            this.refresh_edit_prediction(true, false, window, cx);
20067        });
20068    }
20069
20070    pub fn open_selections_in_multibuffer(
20071        &mut self,
20072        _: &OpenSelectionsInMultibuffer,
20073        window: &mut Window,
20074        cx: &mut Context<Self>,
20075    ) {
20076        let multibuffer = self.buffer.read(cx);
20077
20078        let Some(buffer) = multibuffer.as_singleton() else {
20079            return;
20080        };
20081
20082        let Some(workspace) = self.workspace() else {
20083            return;
20084        };
20085
20086        let title = multibuffer.title(cx).to_string();
20087
20088        let locations = self
20089            .selections
20090            .all_anchors(cx)
20091            .iter()
20092            .map(|selection| {
20093                (
20094                    buffer.clone(),
20095                    (selection.start.text_anchor..selection.end.text_anchor)
20096                        .to_point(buffer.read(cx)),
20097                )
20098            })
20099            .into_group_map();
20100
20101        cx.spawn_in(window, async move |_, cx| {
20102            workspace.update_in(cx, |workspace, window, cx| {
20103                Self::open_locations_in_multibuffer(
20104                    workspace,
20105                    locations,
20106                    format!("Selections for '{title}'"),
20107                    false,
20108                    MultibufferSelectionMode::All,
20109                    window,
20110                    cx,
20111                );
20112            })
20113        })
20114        .detach();
20115    }
20116
20117    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20118    /// last highlight added will be used.
20119    ///
20120    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20121    pub fn highlight_rows<T: 'static>(
20122        &mut self,
20123        range: Range<Anchor>,
20124        color: Hsla,
20125        options: RowHighlightOptions,
20126        cx: &mut Context<Self>,
20127    ) {
20128        let snapshot = self.buffer().read(cx).snapshot(cx);
20129        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20130        let ix = row_highlights.binary_search_by(|highlight| {
20131            Ordering::Equal
20132                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20133                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20134        });
20135
20136        if let Err(mut ix) = ix {
20137            let index = post_inc(&mut self.highlight_order);
20138
20139            // If this range intersects with the preceding highlight, then merge it with
20140            // the preceding highlight. Otherwise insert a new highlight.
20141            let mut merged = false;
20142            if ix > 0 {
20143                let prev_highlight = &mut row_highlights[ix - 1];
20144                if prev_highlight
20145                    .range
20146                    .end
20147                    .cmp(&range.start, &snapshot)
20148                    .is_ge()
20149                {
20150                    ix -= 1;
20151                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20152                        prev_highlight.range.end = range.end;
20153                    }
20154                    merged = true;
20155                    prev_highlight.index = index;
20156                    prev_highlight.color = color;
20157                    prev_highlight.options = options;
20158                }
20159            }
20160
20161            if !merged {
20162                row_highlights.insert(
20163                    ix,
20164                    RowHighlight {
20165                        range,
20166                        index,
20167                        color,
20168                        options,
20169                        type_id: TypeId::of::<T>(),
20170                    },
20171                );
20172            }
20173
20174            // If any of the following highlights intersect with this one, merge them.
20175            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20176                let highlight = &row_highlights[ix];
20177                if next_highlight
20178                    .range
20179                    .start
20180                    .cmp(&highlight.range.end, &snapshot)
20181                    .is_le()
20182                {
20183                    if next_highlight
20184                        .range
20185                        .end
20186                        .cmp(&highlight.range.end, &snapshot)
20187                        .is_gt()
20188                    {
20189                        row_highlights[ix].range.end = next_highlight.range.end;
20190                    }
20191                    row_highlights.remove(ix + 1);
20192                } else {
20193                    break;
20194                }
20195            }
20196        }
20197    }
20198
20199    /// Remove any highlighted row ranges of the given type that intersect the
20200    /// given ranges.
20201    pub fn remove_highlighted_rows<T: 'static>(
20202        &mut self,
20203        ranges_to_remove: Vec<Range<Anchor>>,
20204        cx: &mut Context<Self>,
20205    ) {
20206        let snapshot = self.buffer().read(cx).snapshot(cx);
20207        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20208        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20209        row_highlights.retain(|highlight| {
20210            while let Some(range_to_remove) = ranges_to_remove.peek() {
20211                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20212                    Ordering::Less | Ordering::Equal => {
20213                        ranges_to_remove.next();
20214                    }
20215                    Ordering::Greater => {
20216                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20217                            Ordering::Less | Ordering::Equal => {
20218                                return false;
20219                            }
20220                            Ordering::Greater => break,
20221                        }
20222                    }
20223                }
20224            }
20225
20226            true
20227        })
20228    }
20229
20230    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20231    pub fn clear_row_highlights<T: 'static>(&mut self) {
20232        self.highlighted_rows.remove(&TypeId::of::<T>());
20233    }
20234
20235    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20236    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20237        self.highlighted_rows
20238            .get(&TypeId::of::<T>())
20239            .map_or(&[] as &[_], |vec| vec.as_slice())
20240            .iter()
20241            .map(|highlight| (highlight.range.clone(), highlight.color))
20242    }
20243
20244    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20245    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20246    /// Allows to ignore certain kinds of highlights.
20247    pub fn highlighted_display_rows(
20248        &self,
20249        window: &mut Window,
20250        cx: &mut App,
20251    ) -> BTreeMap<DisplayRow, LineHighlight> {
20252        let snapshot = self.snapshot(window, cx);
20253        let mut used_highlight_orders = HashMap::default();
20254        self.highlighted_rows
20255            .iter()
20256            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20257            .fold(
20258                BTreeMap::<DisplayRow, LineHighlight>::new(),
20259                |mut unique_rows, highlight| {
20260                    let start = highlight.range.start.to_display_point(&snapshot);
20261                    let end = highlight.range.end.to_display_point(&snapshot);
20262                    let start_row = start.row().0;
20263                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20264                        && end.column() == 0
20265                    {
20266                        end.row().0.saturating_sub(1)
20267                    } else {
20268                        end.row().0
20269                    };
20270                    for row in start_row..=end_row {
20271                        let used_index =
20272                            used_highlight_orders.entry(row).or_insert(highlight.index);
20273                        if highlight.index >= *used_index {
20274                            *used_index = highlight.index;
20275                            unique_rows.insert(
20276                                DisplayRow(row),
20277                                LineHighlight {
20278                                    include_gutter: highlight.options.include_gutter,
20279                                    border: None,
20280                                    background: highlight.color.into(),
20281                                    type_id: Some(highlight.type_id),
20282                                },
20283                            );
20284                        }
20285                    }
20286                    unique_rows
20287                },
20288            )
20289    }
20290
20291    pub fn highlighted_display_row_for_autoscroll(
20292        &self,
20293        snapshot: &DisplaySnapshot,
20294    ) -> Option<DisplayRow> {
20295        self.highlighted_rows
20296            .values()
20297            .flat_map(|highlighted_rows| highlighted_rows.iter())
20298            .filter_map(|highlight| {
20299                if highlight.options.autoscroll {
20300                    Some(highlight.range.start.to_display_point(snapshot).row())
20301                } else {
20302                    None
20303                }
20304            })
20305            .min()
20306    }
20307
20308    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20309        self.highlight_background::<SearchWithinRange>(
20310            ranges,
20311            |colors| colors.colors().editor_document_highlight_read_background,
20312            cx,
20313        )
20314    }
20315
20316    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20317        self.breadcrumb_header = Some(new_header);
20318    }
20319
20320    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20321        self.clear_background_highlights::<SearchWithinRange>(cx);
20322    }
20323
20324    pub fn highlight_background<T: 'static>(
20325        &mut self,
20326        ranges: &[Range<Anchor>],
20327        color_fetcher: fn(&Theme) -> Hsla,
20328        cx: &mut Context<Self>,
20329    ) {
20330        self.background_highlights.insert(
20331            HighlightKey::Type(TypeId::of::<T>()),
20332            (color_fetcher, Arc::from(ranges)),
20333        );
20334        self.scrollbar_marker_state.dirty = true;
20335        cx.notify();
20336    }
20337
20338    pub fn highlight_background_key<T: 'static>(
20339        &mut self,
20340        key: usize,
20341        ranges: &[Range<Anchor>],
20342        color_fetcher: fn(&Theme) -> Hsla,
20343        cx: &mut Context<Self>,
20344    ) {
20345        self.background_highlights.insert(
20346            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20347            (color_fetcher, Arc::from(ranges)),
20348        );
20349        self.scrollbar_marker_state.dirty = true;
20350        cx.notify();
20351    }
20352
20353    pub fn clear_background_highlights<T: 'static>(
20354        &mut self,
20355        cx: &mut Context<Self>,
20356    ) -> Option<BackgroundHighlight> {
20357        let text_highlights = self
20358            .background_highlights
20359            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20360        if !text_highlights.1.is_empty() {
20361            self.scrollbar_marker_state.dirty = true;
20362            cx.notify();
20363        }
20364        Some(text_highlights)
20365    }
20366
20367    pub fn highlight_gutter<T: 'static>(
20368        &mut self,
20369        ranges: impl Into<Vec<Range<Anchor>>>,
20370        color_fetcher: fn(&App) -> Hsla,
20371        cx: &mut Context<Self>,
20372    ) {
20373        self.gutter_highlights
20374            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20375        cx.notify();
20376    }
20377
20378    pub fn clear_gutter_highlights<T: 'static>(
20379        &mut self,
20380        cx: &mut Context<Self>,
20381    ) -> Option<GutterHighlight> {
20382        cx.notify();
20383        self.gutter_highlights.remove(&TypeId::of::<T>())
20384    }
20385
20386    pub fn insert_gutter_highlight<T: 'static>(
20387        &mut self,
20388        range: Range<Anchor>,
20389        color_fetcher: fn(&App) -> Hsla,
20390        cx: &mut Context<Self>,
20391    ) {
20392        let snapshot = self.buffer().read(cx).snapshot(cx);
20393        let mut highlights = self
20394            .gutter_highlights
20395            .remove(&TypeId::of::<T>())
20396            .map(|(_, highlights)| highlights)
20397            .unwrap_or_default();
20398        let ix = highlights.binary_search_by(|highlight| {
20399            Ordering::Equal
20400                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20401                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20402        });
20403        if let Err(ix) = ix {
20404            highlights.insert(ix, range);
20405        }
20406        self.gutter_highlights
20407            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20408    }
20409
20410    pub fn remove_gutter_highlights<T: 'static>(
20411        &mut self,
20412        ranges_to_remove: Vec<Range<Anchor>>,
20413        cx: &mut Context<Self>,
20414    ) {
20415        let snapshot = self.buffer().read(cx).snapshot(cx);
20416        let Some((color_fetcher, mut gutter_highlights)) =
20417            self.gutter_highlights.remove(&TypeId::of::<T>())
20418        else {
20419            return;
20420        };
20421        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20422        gutter_highlights.retain(|highlight| {
20423            while let Some(range_to_remove) = ranges_to_remove.peek() {
20424                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20425                    Ordering::Less | Ordering::Equal => {
20426                        ranges_to_remove.next();
20427                    }
20428                    Ordering::Greater => {
20429                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20430                            Ordering::Less | Ordering::Equal => {
20431                                return false;
20432                            }
20433                            Ordering::Greater => break,
20434                        }
20435                    }
20436                }
20437            }
20438
20439            true
20440        });
20441        self.gutter_highlights
20442            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20443    }
20444
20445    #[cfg(feature = "test-support")]
20446    pub fn all_text_highlights(
20447        &self,
20448        window: &mut Window,
20449        cx: &mut Context<Self>,
20450    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20451        let snapshot = self.snapshot(window, cx);
20452        self.display_map.update(cx, |display_map, _| {
20453            display_map
20454                .all_text_highlights()
20455                .map(|highlight| {
20456                    let (style, ranges) = highlight.as_ref();
20457                    (
20458                        *style,
20459                        ranges
20460                            .iter()
20461                            .map(|range| range.clone().to_display_points(&snapshot))
20462                            .collect(),
20463                    )
20464                })
20465                .collect()
20466        })
20467    }
20468
20469    #[cfg(feature = "test-support")]
20470    pub fn all_text_background_highlights(
20471        &self,
20472        window: &mut Window,
20473        cx: &mut Context<Self>,
20474    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20475        let snapshot = self.snapshot(window, cx);
20476        let buffer = &snapshot.buffer_snapshot();
20477        let start = buffer.anchor_before(0);
20478        let end = buffer.anchor_after(buffer.len());
20479        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20480    }
20481
20482    #[cfg(any(test, feature = "test-support"))]
20483    pub fn sorted_background_highlights_in_range(
20484        &self,
20485        search_range: Range<Anchor>,
20486        display_snapshot: &DisplaySnapshot,
20487        theme: &Theme,
20488    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20489        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20490        res.sort_by(|a, b| {
20491            a.0.start
20492                .cmp(&b.0.start)
20493                .then_with(|| a.0.end.cmp(&b.0.end))
20494                .then_with(|| a.1.cmp(&b.1))
20495        });
20496        res
20497    }
20498
20499    #[cfg(feature = "test-support")]
20500    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20501        let snapshot = self.buffer().read(cx).snapshot(cx);
20502
20503        let highlights = self
20504            .background_highlights
20505            .get(&HighlightKey::Type(TypeId::of::<
20506                items::BufferSearchHighlights,
20507            >()));
20508
20509        if let Some((_color, ranges)) = highlights {
20510            ranges
20511                .iter()
20512                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20513                .collect_vec()
20514        } else {
20515            vec![]
20516        }
20517    }
20518
20519    fn document_highlights_for_position<'a>(
20520        &'a self,
20521        position: Anchor,
20522        buffer: &'a MultiBufferSnapshot,
20523    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20524        let read_highlights = self
20525            .background_highlights
20526            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20527            .map(|h| &h.1);
20528        let write_highlights = self
20529            .background_highlights
20530            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20531            .map(|h| &h.1);
20532        let left_position = position.bias_left(buffer);
20533        let right_position = position.bias_right(buffer);
20534        read_highlights
20535            .into_iter()
20536            .chain(write_highlights)
20537            .flat_map(move |ranges| {
20538                let start_ix = match ranges.binary_search_by(|probe| {
20539                    let cmp = probe.end.cmp(&left_position, buffer);
20540                    if cmp.is_ge() {
20541                        Ordering::Greater
20542                    } else {
20543                        Ordering::Less
20544                    }
20545                }) {
20546                    Ok(i) | Err(i) => i,
20547                };
20548
20549                ranges[start_ix..]
20550                    .iter()
20551                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20552            })
20553    }
20554
20555    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20556        self.background_highlights
20557            .get(&HighlightKey::Type(TypeId::of::<T>()))
20558            .is_some_and(|(_, highlights)| !highlights.is_empty())
20559    }
20560
20561    /// Returns all background highlights for a given range.
20562    ///
20563    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20564    pub fn background_highlights_in_range(
20565        &self,
20566        search_range: Range<Anchor>,
20567        display_snapshot: &DisplaySnapshot,
20568        theme: &Theme,
20569    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20570        let mut results = Vec::new();
20571        for (color_fetcher, ranges) in self.background_highlights.values() {
20572            let color = color_fetcher(theme);
20573            let start_ix = match ranges.binary_search_by(|probe| {
20574                let cmp = probe
20575                    .end
20576                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20577                if cmp.is_gt() {
20578                    Ordering::Greater
20579                } else {
20580                    Ordering::Less
20581                }
20582            }) {
20583                Ok(i) | Err(i) => i,
20584            };
20585            for range in &ranges[start_ix..] {
20586                if range
20587                    .start
20588                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20589                    .is_ge()
20590                {
20591                    break;
20592                }
20593
20594                let start = range.start.to_display_point(display_snapshot);
20595                let end = range.end.to_display_point(display_snapshot);
20596                results.push((start..end, color))
20597            }
20598        }
20599        results
20600    }
20601
20602    pub fn gutter_highlights_in_range(
20603        &self,
20604        search_range: Range<Anchor>,
20605        display_snapshot: &DisplaySnapshot,
20606        cx: &App,
20607    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20608        let mut results = Vec::new();
20609        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20610            let color = color_fetcher(cx);
20611            let start_ix = match ranges.binary_search_by(|probe| {
20612                let cmp = probe
20613                    .end
20614                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20615                if cmp.is_gt() {
20616                    Ordering::Greater
20617                } else {
20618                    Ordering::Less
20619                }
20620            }) {
20621                Ok(i) | Err(i) => i,
20622            };
20623            for range in &ranges[start_ix..] {
20624                if range
20625                    .start
20626                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20627                    .is_ge()
20628                {
20629                    break;
20630                }
20631
20632                let start = range.start.to_display_point(display_snapshot);
20633                let end = range.end.to_display_point(display_snapshot);
20634                results.push((start..end, color))
20635            }
20636        }
20637        results
20638    }
20639
20640    /// Get the text ranges corresponding to the redaction query
20641    pub fn redacted_ranges(
20642        &self,
20643        search_range: Range<Anchor>,
20644        display_snapshot: &DisplaySnapshot,
20645        cx: &App,
20646    ) -> Vec<Range<DisplayPoint>> {
20647        display_snapshot
20648            .buffer_snapshot()
20649            .redacted_ranges(search_range, |file| {
20650                if let Some(file) = file {
20651                    file.is_private()
20652                        && EditorSettings::get(
20653                            Some(SettingsLocation {
20654                                worktree_id: file.worktree_id(cx),
20655                                path: file.path().as_ref(),
20656                            }),
20657                            cx,
20658                        )
20659                        .redact_private_values
20660                } else {
20661                    false
20662                }
20663            })
20664            .map(|range| {
20665                range.start.to_display_point(display_snapshot)
20666                    ..range.end.to_display_point(display_snapshot)
20667            })
20668            .collect()
20669    }
20670
20671    pub fn highlight_text_key<T: 'static>(
20672        &mut self,
20673        key: usize,
20674        ranges: Vec<Range<Anchor>>,
20675        style: HighlightStyle,
20676        cx: &mut Context<Self>,
20677    ) {
20678        self.display_map.update(cx, |map, _| {
20679            map.highlight_text(
20680                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20681                ranges,
20682                style,
20683            );
20684        });
20685        cx.notify();
20686    }
20687
20688    pub fn highlight_text<T: 'static>(
20689        &mut self,
20690        ranges: Vec<Range<Anchor>>,
20691        style: HighlightStyle,
20692        cx: &mut Context<Self>,
20693    ) {
20694        self.display_map.update(cx, |map, _| {
20695            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20696        });
20697        cx.notify();
20698    }
20699
20700    pub(crate) fn highlight_inlays<T: 'static>(
20701        &mut self,
20702        highlights: Vec<InlayHighlight>,
20703        style: HighlightStyle,
20704        cx: &mut Context<Self>,
20705    ) {
20706        self.display_map.update(cx, |map, _| {
20707            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20708        });
20709        cx.notify();
20710    }
20711
20712    pub fn text_highlights<'a, T: 'static>(
20713        &'a self,
20714        cx: &'a App,
20715    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20716        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20717    }
20718
20719    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20720        let cleared = self
20721            .display_map
20722            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20723        if cleared {
20724            cx.notify();
20725        }
20726    }
20727
20728    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20729        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20730            && self.focus_handle.is_focused(window)
20731    }
20732
20733    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20734        self.show_cursor_when_unfocused = is_enabled;
20735        cx.notify();
20736    }
20737
20738    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20739        cx.notify();
20740    }
20741
20742    fn on_debug_session_event(
20743        &mut self,
20744        _session: Entity<Session>,
20745        event: &SessionEvent,
20746        cx: &mut Context<Self>,
20747    ) {
20748        if let SessionEvent::InvalidateInlineValue = event {
20749            self.refresh_inline_values(cx);
20750        }
20751    }
20752
20753    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20754        let Some(project) = self.project.clone() else {
20755            return;
20756        };
20757
20758        if !self.inline_value_cache.enabled {
20759            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20760            self.splice_inlays(&inlays, Vec::new(), cx);
20761            return;
20762        }
20763
20764        let current_execution_position = self
20765            .highlighted_rows
20766            .get(&TypeId::of::<ActiveDebugLine>())
20767            .and_then(|lines| lines.last().map(|line| line.range.end));
20768
20769        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20770            let inline_values = editor
20771                .update(cx, |editor, cx| {
20772                    let Some(current_execution_position) = current_execution_position else {
20773                        return Some(Task::ready(Ok(Vec::new())));
20774                    };
20775
20776                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20777                        let snapshot = buffer.snapshot(cx);
20778
20779                        let excerpt = snapshot.excerpt_containing(
20780                            current_execution_position..current_execution_position,
20781                        )?;
20782
20783                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20784                    })?;
20785
20786                    let range =
20787                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20788
20789                    project.inline_values(buffer, range, cx)
20790                })
20791                .ok()
20792                .flatten()?
20793                .await
20794                .context("refreshing debugger inlays")
20795                .log_err()?;
20796
20797            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20798
20799            for (buffer_id, inline_value) in inline_values
20800                .into_iter()
20801                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20802            {
20803                buffer_inline_values
20804                    .entry(buffer_id)
20805                    .or_default()
20806                    .push(inline_value);
20807            }
20808
20809            editor
20810                .update(cx, |editor, cx| {
20811                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20812                    let mut new_inlays = Vec::default();
20813
20814                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20815                        let buffer_id = buffer_snapshot.remote_id();
20816                        buffer_inline_values
20817                            .get(&buffer_id)
20818                            .into_iter()
20819                            .flatten()
20820                            .for_each(|hint| {
20821                                let inlay = Inlay::debugger(
20822                                    post_inc(&mut editor.next_inlay_id),
20823                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20824                                    hint.text(),
20825                                );
20826                                if !inlay.text().chars().contains(&'\n') {
20827                                    new_inlays.push(inlay);
20828                                }
20829                            });
20830                    }
20831
20832                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20833                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20834
20835                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20836                })
20837                .ok()?;
20838            Some(())
20839        });
20840    }
20841
20842    fn on_buffer_event(
20843        &mut self,
20844        multibuffer: &Entity<MultiBuffer>,
20845        event: &multi_buffer::Event,
20846        window: &mut Window,
20847        cx: &mut Context<Self>,
20848    ) {
20849        match event {
20850            multi_buffer::Event::Edited {
20851                singleton_buffer_edited,
20852                edited_buffer,
20853            } => {
20854                self.scrollbar_marker_state.dirty = true;
20855                self.active_indent_guides_state.dirty = true;
20856                self.refresh_active_diagnostics(cx);
20857                self.refresh_code_actions(window, cx);
20858                self.refresh_selected_text_highlights(true, window, cx);
20859                self.refresh_single_line_folds(window, cx);
20860                refresh_matching_bracket_highlights(self, cx);
20861                if self.has_active_edit_prediction() {
20862                    self.update_visible_edit_prediction(window, cx);
20863                }
20864                if let Some(project) = self.project.as_ref()
20865                    && let Some(edited_buffer) = edited_buffer
20866                {
20867                    project.update(cx, |project, cx| {
20868                        self.registered_buffers
20869                            .entry(edited_buffer.read(cx).remote_id())
20870                            .or_insert_with(|| {
20871                                project.register_buffer_with_language_servers(edited_buffer, cx)
20872                            });
20873                    });
20874                }
20875                cx.emit(EditorEvent::BufferEdited);
20876                cx.emit(SearchEvent::MatchesInvalidated);
20877
20878                if let Some(buffer) = edited_buffer {
20879                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20880                }
20881
20882                if *singleton_buffer_edited {
20883                    if let Some(buffer) = edited_buffer
20884                        && buffer.read(cx).file().is_none()
20885                    {
20886                        cx.emit(EditorEvent::TitleChanged);
20887                    }
20888                    if let Some(project) = &self.project {
20889                        #[allow(clippy::mutable_key_type)]
20890                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20891                            multibuffer
20892                                .all_buffers()
20893                                .into_iter()
20894                                .filter_map(|buffer| {
20895                                    buffer.update(cx, |buffer, cx| {
20896                                        let language = buffer.language()?;
20897                                        let should_discard = project.update(cx, |project, cx| {
20898                                            project.is_local()
20899                                                && !project.has_language_servers_for(buffer, cx)
20900                                        });
20901                                        should_discard.not().then_some(language.clone())
20902                                    })
20903                                })
20904                                .collect::<HashSet<_>>()
20905                        });
20906                        if !languages_affected.is_empty() {
20907                            self.refresh_inlay_hints(
20908                                InlayHintRefreshReason::BufferEdited(languages_affected),
20909                                cx,
20910                            );
20911                        }
20912                    }
20913                }
20914
20915                let Some(project) = &self.project else { return };
20916                let (telemetry, is_via_ssh) = {
20917                    let project = project.read(cx);
20918                    let telemetry = project.client().telemetry().clone();
20919                    let is_via_ssh = project.is_via_remote_server();
20920                    (telemetry, is_via_ssh)
20921                };
20922                refresh_linked_ranges(self, window, cx);
20923                telemetry.log_edit_event("editor", is_via_ssh);
20924            }
20925            multi_buffer::Event::ExcerptsAdded {
20926                buffer,
20927                predecessor,
20928                excerpts,
20929            } => {
20930                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20931                let buffer_id = buffer.read(cx).remote_id();
20932                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20933                    && let Some(project) = &self.project
20934                {
20935                    update_uncommitted_diff_for_buffer(
20936                        cx.entity(),
20937                        project,
20938                        [buffer.clone()],
20939                        self.buffer.clone(),
20940                        cx,
20941                    )
20942                    .detach();
20943                }
20944                if self.active_diagnostics != ActiveDiagnostic::All {
20945                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20946                }
20947                cx.emit(EditorEvent::ExcerptsAdded {
20948                    buffer: buffer.clone(),
20949                    predecessor: *predecessor,
20950                    excerpts: excerpts.clone(),
20951                });
20952                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20953            }
20954            multi_buffer::Event::ExcerptsRemoved {
20955                ids,
20956                removed_buffer_ids,
20957            } => {
20958                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20959                let buffer = self.buffer.read(cx);
20960                self.registered_buffers
20961                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20962                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20963                cx.emit(EditorEvent::ExcerptsRemoved {
20964                    ids: ids.clone(),
20965                    removed_buffer_ids: removed_buffer_ids.clone(),
20966                });
20967            }
20968            multi_buffer::Event::ExcerptsEdited {
20969                excerpt_ids,
20970                buffer_ids,
20971            } => {
20972                self.display_map.update(cx, |map, cx| {
20973                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20974                });
20975                cx.emit(EditorEvent::ExcerptsEdited {
20976                    ids: excerpt_ids.clone(),
20977                });
20978            }
20979            multi_buffer::Event::ExcerptsExpanded { ids } => {
20980                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20981                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20982            }
20983            multi_buffer::Event::Reparsed(buffer_id) => {
20984                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20985                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20986
20987                cx.emit(EditorEvent::Reparsed(*buffer_id));
20988            }
20989            multi_buffer::Event::DiffHunksToggled => {
20990                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20991            }
20992            multi_buffer::Event::LanguageChanged(buffer_id) => {
20993                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20994                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20995                cx.emit(EditorEvent::Reparsed(*buffer_id));
20996                cx.notify();
20997            }
20998            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20999            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21000            multi_buffer::Event::FileHandleChanged
21001            | multi_buffer::Event::Reloaded
21002            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21003            multi_buffer::Event::DiagnosticsUpdated => {
21004                self.update_diagnostics_state(window, cx);
21005            }
21006            _ => {}
21007        };
21008    }
21009
21010    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21011        if !self.diagnostics_enabled() {
21012            return;
21013        }
21014        self.refresh_active_diagnostics(cx);
21015        self.refresh_inline_diagnostics(true, window, cx);
21016        self.scrollbar_marker_state.dirty = true;
21017        cx.notify();
21018    }
21019
21020    pub fn start_temporary_diff_override(&mut self) {
21021        self.load_diff_task.take();
21022        self.temporary_diff_override = true;
21023    }
21024
21025    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21026        self.temporary_diff_override = false;
21027        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21028        self.buffer.update(cx, |buffer, cx| {
21029            buffer.set_all_diff_hunks_collapsed(cx);
21030        });
21031
21032        if let Some(project) = self.project.clone() {
21033            self.load_diff_task = Some(
21034                update_uncommitted_diff_for_buffer(
21035                    cx.entity(),
21036                    &project,
21037                    self.buffer.read(cx).all_buffers(),
21038                    self.buffer.clone(),
21039                    cx,
21040                )
21041                .shared(),
21042            );
21043        }
21044    }
21045
21046    fn on_display_map_changed(
21047        &mut self,
21048        _: Entity<DisplayMap>,
21049        _: &mut Window,
21050        cx: &mut Context<Self>,
21051    ) {
21052        cx.notify();
21053    }
21054
21055    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21056        if self.diagnostics_enabled() {
21057            let new_severity = EditorSettings::get_global(cx)
21058                .diagnostics_max_severity
21059                .unwrap_or(DiagnosticSeverity::Hint);
21060            self.set_max_diagnostics_severity(new_severity, cx);
21061        }
21062        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21063        self.update_edit_prediction_settings(cx);
21064        self.refresh_edit_prediction(true, false, window, cx);
21065        self.refresh_inline_values(cx);
21066        self.refresh_inlay_hints(
21067            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21068                self.selections.newest_anchor().head(),
21069                &self.buffer.read(cx).snapshot(cx),
21070                cx,
21071            )),
21072            cx,
21073        );
21074
21075        let old_cursor_shape = self.cursor_shape;
21076        let old_show_breadcrumbs = self.show_breadcrumbs;
21077
21078        {
21079            let editor_settings = EditorSettings::get_global(cx);
21080            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21081            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21082            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21083            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21084        }
21085
21086        if old_cursor_shape != self.cursor_shape {
21087            cx.emit(EditorEvent::CursorShapeChanged);
21088        }
21089
21090        if old_show_breadcrumbs != self.show_breadcrumbs {
21091            cx.emit(EditorEvent::BreadcrumbsChanged);
21092        }
21093
21094        let project_settings = ProjectSettings::get_global(cx);
21095        self.serialize_dirty_buffers =
21096            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21097
21098        if self.mode.is_full() {
21099            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21100            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21101            if self.show_inline_diagnostics != show_inline_diagnostics {
21102                self.show_inline_diagnostics = show_inline_diagnostics;
21103                self.refresh_inline_diagnostics(false, window, cx);
21104            }
21105
21106            if self.git_blame_inline_enabled != inline_blame_enabled {
21107                self.toggle_git_blame_inline_internal(false, window, cx);
21108            }
21109
21110            let minimap_settings = EditorSettings::get_global(cx).minimap;
21111            if self.minimap_visibility != MinimapVisibility::Disabled {
21112                if self.minimap_visibility.settings_visibility()
21113                    != minimap_settings.minimap_enabled()
21114                {
21115                    self.set_minimap_visibility(
21116                        MinimapVisibility::for_mode(self.mode(), cx),
21117                        window,
21118                        cx,
21119                    );
21120                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21121                    minimap_entity.update(cx, |minimap_editor, cx| {
21122                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21123                    })
21124                }
21125            }
21126        }
21127
21128        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21129            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21130        }) {
21131            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21132                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21133            }
21134            self.refresh_colors(false, None, window, cx);
21135        }
21136
21137        cx.notify();
21138    }
21139
21140    pub fn set_searchable(&mut self, searchable: bool) {
21141        self.searchable = searchable;
21142    }
21143
21144    pub fn searchable(&self) -> bool {
21145        self.searchable
21146    }
21147
21148    fn open_proposed_changes_editor(
21149        &mut self,
21150        _: &OpenProposedChangesEditor,
21151        window: &mut Window,
21152        cx: &mut Context<Self>,
21153    ) {
21154        let Some(workspace) = self.workspace() else {
21155            cx.propagate();
21156            return;
21157        };
21158
21159        let selections = self.selections.all::<usize>(cx);
21160        let multi_buffer = self.buffer.read(cx);
21161        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21162        let mut new_selections_by_buffer = HashMap::default();
21163        for selection in selections {
21164            for (buffer, range, _) in
21165                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21166            {
21167                let mut range = range.to_point(buffer);
21168                range.start.column = 0;
21169                range.end.column = buffer.line_len(range.end.row);
21170                new_selections_by_buffer
21171                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21172                    .or_insert(Vec::new())
21173                    .push(range)
21174            }
21175        }
21176
21177        let proposed_changes_buffers = new_selections_by_buffer
21178            .into_iter()
21179            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21180            .collect::<Vec<_>>();
21181        let proposed_changes_editor = cx.new(|cx| {
21182            ProposedChangesEditor::new(
21183                "Proposed changes",
21184                proposed_changes_buffers,
21185                self.project.clone(),
21186                window,
21187                cx,
21188            )
21189        });
21190
21191        window.defer(cx, move |window, cx| {
21192            workspace.update(cx, |workspace, cx| {
21193                workspace.active_pane().update(cx, |pane, cx| {
21194                    pane.add_item(
21195                        Box::new(proposed_changes_editor),
21196                        true,
21197                        true,
21198                        None,
21199                        window,
21200                        cx,
21201                    );
21202                });
21203            });
21204        });
21205    }
21206
21207    pub fn open_excerpts_in_split(
21208        &mut self,
21209        _: &OpenExcerptsSplit,
21210        window: &mut Window,
21211        cx: &mut Context<Self>,
21212    ) {
21213        self.open_excerpts_common(None, true, window, cx)
21214    }
21215
21216    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21217        self.open_excerpts_common(None, false, window, cx)
21218    }
21219
21220    fn open_excerpts_common(
21221        &mut self,
21222        jump_data: Option<JumpData>,
21223        split: bool,
21224        window: &mut Window,
21225        cx: &mut Context<Self>,
21226    ) {
21227        let Some(workspace) = self.workspace() else {
21228            cx.propagate();
21229            return;
21230        };
21231
21232        if self.buffer.read(cx).is_singleton() {
21233            cx.propagate();
21234            return;
21235        }
21236
21237        let mut new_selections_by_buffer = HashMap::default();
21238        match &jump_data {
21239            Some(JumpData::MultiBufferPoint {
21240                excerpt_id,
21241                position,
21242                anchor,
21243                line_offset_from_top,
21244            }) => {
21245                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21246                if let Some(buffer) = multi_buffer_snapshot
21247                    .buffer_id_for_excerpt(*excerpt_id)
21248                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21249                {
21250                    let buffer_snapshot = buffer.read(cx).snapshot();
21251                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21252                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21253                    } else {
21254                        buffer_snapshot.clip_point(*position, Bias::Left)
21255                    };
21256                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21257                    new_selections_by_buffer.insert(
21258                        buffer,
21259                        (
21260                            vec![jump_to_offset..jump_to_offset],
21261                            Some(*line_offset_from_top),
21262                        ),
21263                    );
21264                }
21265            }
21266            Some(JumpData::MultiBufferRow {
21267                row,
21268                line_offset_from_top,
21269            }) => {
21270                let point = MultiBufferPoint::new(row.0, 0);
21271                if let Some((buffer, buffer_point, _)) =
21272                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21273                {
21274                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21275                    new_selections_by_buffer
21276                        .entry(buffer)
21277                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21278                        .0
21279                        .push(buffer_offset..buffer_offset)
21280                }
21281            }
21282            None => {
21283                let selections = self.selections.all::<usize>(cx);
21284                let multi_buffer = self.buffer.read(cx);
21285                for selection in selections {
21286                    for (snapshot, range, _, anchor) in multi_buffer
21287                        .snapshot(cx)
21288                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21289                    {
21290                        if let Some(anchor) = anchor {
21291                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21292                            else {
21293                                continue;
21294                            };
21295                            let offset = text::ToOffset::to_offset(
21296                                &anchor.text_anchor,
21297                                &buffer_handle.read(cx).snapshot(),
21298                            );
21299                            let range = offset..offset;
21300                            new_selections_by_buffer
21301                                .entry(buffer_handle)
21302                                .or_insert((Vec::new(), None))
21303                                .0
21304                                .push(range)
21305                        } else {
21306                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21307                            else {
21308                                continue;
21309                            };
21310                            new_selections_by_buffer
21311                                .entry(buffer_handle)
21312                                .or_insert((Vec::new(), None))
21313                                .0
21314                                .push(range)
21315                        }
21316                    }
21317                }
21318            }
21319        }
21320
21321        new_selections_by_buffer
21322            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21323
21324        if new_selections_by_buffer.is_empty() {
21325            return;
21326        }
21327
21328        // We defer the pane interaction because we ourselves are a workspace item
21329        // and activating a new item causes the pane to call a method on us reentrantly,
21330        // which panics if we're on the stack.
21331        window.defer(cx, move |window, cx| {
21332            workspace.update(cx, |workspace, cx| {
21333                let pane = if split {
21334                    workspace.adjacent_pane(window, cx)
21335                } else {
21336                    workspace.active_pane().clone()
21337                };
21338
21339                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21340                    let editor = buffer
21341                        .read(cx)
21342                        .file()
21343                        .is_none()
21344                        .then(|| {
21345                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21346                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21347                            // Instead, we try to activate the existing editor in the pane first.
21348                            let (editor, pane_item_index) =
21349                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21350                                    let editor = item.downcast::<Editor>()?;
21351                                    let singleton_buffer =
21352                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21353                                    if singleton_buffer == buffer {
21354                                        Some((editor, i))
21355                                    } else {
21356                                        None
21357                                    }
21358                                })?;
21359                            pane.update(cx, |pane, cx| {
21360                                pane.activate_item(pane_item_index, true, true, window, cx)
21361                            });
21362                            Some(editor)
21363                        })
21364                        .flatten()
21365                        .unwrap_or_else(|| {
21366                            workspace.open_project_item::<Self>(
21367                                pane.clone(),
21368                                buffer,
21369                                true,
21370                                true,
21371                                window,
21372                                cx,
21373                            )
21374                        });
21375
21376                    editor.update(cx, |editor, cx| {
21377                        let autoscroll = match scroll_offset {
21378                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21379                            None => Autoscroll::newest(),
21380                        };
21381                        let nav_history = editor.nav_history.take();
21382                        editor.change_selections(
21383                            SelectionEffects::scroll(autoscroll),
21384                            window,
21385                            cx,
21386                            |s| {
21387                                s.select_ranges(ranges);
21388                            },
21389                        );
21390                        editor.nav_history = nav_history;
21391                    });
21392                }
21393            })
21394        });
21395    }
21396
21397    // For now, don't allow opening excerpts in buffers that aren't backed by
21398    // regular project files.
21399    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21400        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21401    }
21402
21403    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21404        let snapshot = self.buffer.read(cx).read(cx);
21405        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21406        Some(
21407            ranges
21408                .iter()
21409                .map(move |range| {
21410                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21411                })
21412                .collect(),
21413        )
21414    }
21415
21416    fn selection_replacement_ranges(
21417        &self,
21418        range: Range<OffsetUtf16>,
21419        cx: &mut App,
21420    ) -> Vec<Range<OffsetUtf16>> {
21421        let selections = self.selections.all::<OffsetUtf16>(cx);
21422        let newest_selection = selections
21423            .iter()
21424            .max_by_key(|selection| selection.id)
21425            .unwrap();
21426        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21427        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21428        let snapshot = self.buffer.read(cx).read(cx);
21429        selections
21430            .into_iter()
21431            .map(|mut selection| {
21432                selection.start.0 =
21433                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21434                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21435                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21436                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21437            })
21438            .collect()
21439    }
21440
21441    fn report_editor_event(
21442        &self,
21443        reported_event: ReportEditorEvent,
21444        file_extension: Option<String>,
21445        cx: &App,
21446    ) {
21447        if cfg!(any(test, feature = "test-support")) {
21448            return;
21449        }
21450
21451        let Some(project) = &self.project else { return };
21452
21453        // If None, we are in a file without an extension
21454        let file = self
21455            .buffer
21456            .read(cx)
21457            .as_singleton()
21458            .and_then(|b| b.read(cx).file());
21459        let file_extension = file_extension.or(file
21460            .as_ref()
21461            .and_then(|file| Path::new(file.file_name(cx)).extension())
21462            .and_then(|e| e.to_str())
21463            .map(|a| a.to_string()));
21464
21465        let vim_mode = vim_enabled(cx);
21466
21467        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21468        let copilot_enabled = edit_predictions_provider
21469            == language::language_settings::EditPredictionProvider::Copilot;
21470        let copilot_enabled_for_language = self
21471            .buffer
21472            .read(cx)
21473            .language_settings(cx)
21474            .show_edit_predictions;
21475
21476        let project = project.read(cx);
21477        let event_type = reported_event.event_type();
21478
21479        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21480            telemetry::event!(
21481                event_type,
21482                type = if auto_saved {"autosave"} else {"manual"},
21483                file_extension,
21484                vim_mode,
21485                copilot_enabled,
21486                copilot_enabled_for_language,
21487                edit_predictions_provider,
21488                is_via_ssh = project.is_via_remote_server(),
21489            );
21490        } else {
21491            telemetry::event!(
21492                event_type,
21493                file_extension,
21494                vim_mode,
21495                copilot_enabled,
21496                copilot_enabled_for_language,
21497                edit_predictions_provider,
21498                is_via_ssh = project.is_via_remote_server(),
21499            );
21500        };
21501    }
21502
21503    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21504    /// with each line being an array of {text, highlight} objects.
21505    fn copy_highlight_json(
21506        &mut self,
21507        _: &CopyHighlightJson,
21508        window: &mut Window,
21509        cx: &mut Context<Self>,
21510    ) {
21511        #[derive(Serialize)]
21512        struct Chunk<'a> {
21513            text: String,
21514            highlight: Option<&'a str>,
21515        }
21516
21517        let snapshot = self.buffer.read(cx).snapshot(cx);
21518        let range = self
21519            .selected_text_range(false, window, cx)
21520            .and_then(|selection| {
21521                if selection.range.is_empty() {
21522                    None
21523                } else {
21524                    Some(selection.range)
21525                }
21526            })
21527            .unwrap_or_else(|| 0..snapshot.len());
21528
21529        let chunks = snapshot.chunks(range, true);
21530        let mut lines = Vec::new();
21531        let mut line: VecDeque<Chunk> = VecDeque::new();
21532
21533        let Some(style) = self.style.as_ref() else {
21534            return;
21535        };
21536
21537        for chunk in chunks {
21538            let highlight = chunk
21539                .syntax_highlight_id
21540                .and_then(|id| id.name(&style.syntax));
21541            let mut chunk_lines = chunk.text.split('\n').peekable();
21542            while let Some(text) = chunk_lines.next() {
21543                let mut merged_with_last_token = false;
21544                if let Some(last_token) = line.back_mut()
21545                    && last_token.highlight == highlight
21546                {
21547                    last_token.text.push_str(text);
21548                    merged_with_last_token = true;
21549                }
21550
21551                if !merged_with_last_token {
21552                    line.push_back(Chunk {
21553                        text: text.into(),
21554                        highlight,
21555                    });
21556                }
21557
21558                if chunk_lines.peek().is_some() {
21559                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21560                        line.pop_front();
21561                    }
21562                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21563                        line.pop_back();
21564                    }
21565
21566                    lines.push(mem::take(&mut line));
21567                }
21568            }
21569        }
21570
21571        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21572            return;
21573        };
21574        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21575    }
21576
21577    pub fn open_context_menu(
21578        &mut self,
21579        _: &OpenContextMenu,
21580        window: &mut Window,
21581        cx: &mut Context<Self>,
21582    ) {
21583        self.request_autoscroll(Autoscroll::newest(), cx);
21584        let position = self.selections.newest_display(cx).start;
21585        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21586    }
21587
21588    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21589        &self.inlay_hint_cache
21590    }
21591
21592    pub fn replay_insert_event(
21593        &mut self,
21594        text: &str,
21595        relative_utf16_range: Option<Range<isize>>,
21596        window: &mut Window,
21597        cx: &mut Context<Self>,
21598    ) {
21599        if !self.input_enabled {
21600            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21601            return;
21602        }
21603        if let Some(relative_utf16_range) = relative_utf16_range {
21604            let selections = self.selections.all::<OffsetUtf16>(cx);
21605            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21606                let new_ranges = selections.into_iter().map(|range| {
21607                    let start = OffsetUtf16(
21608                        range
21609                            .head()
21610                            .0
21611                            .saturating_add_signed(relative_utf16_range.start),
21612                    );
21613                    let end = OffsetUtf16(
21614                        range
21615                            .head()
21616                            .0
21617                            .saturating_add_signed(relative_utf16_range.end),
21618                    );
21619                    start..end
21620                });
21621                s.select_ranges(new_ranges);
21622            });
21623        }
21624
21625        self.handle_input(text, window, cx);
21626    }
21627
21628    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21629        let Some(provider) = self.semantics_provider.as_ref() else {
21630            return false;
21631        };
21632
21633        let mut supports = false;
21634        self.buffer().update(cx, |this, cx| {
21635            this.for_each_buffer(|buffer| {
21636                supports |= provider.supports_inlay_hints(buffer, cx);
21637            });
21638        });
21639
21640        supports
21641    }
21642
21643    pub fn is_focused(&self, window: &Window) -> bool {
21644        self.focus_handle.is_focused(window)
21645    }
21646
21647    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21648        cx.emit(EditorEvent::Focused);
21649
21650        if let Some(descendant) = self
21651            .last_focused_descendant
21652            .take()
21653            .and_then(|descendant| descendant.upgrade())
21654        {
21655            window.focus(&descendant);
21656        } else {
21657            if let Some(blame) = self.blame.as_ref() {
21658                blame.update(cx, GitBlame::focus)
21659            }
21660
21661            self.blink_manager.update(cx, BlinkManager::enable);
21662            self.show_cursor_names(window, cx);
21663            self.buffer.update(cx, |buffer, cx| {
21664                buffer.finalize_last_transaction(cx);
21665                if self.leader_id.is_none() {
21666                    buffer.set_active_selections(
21667                        &self.selections.disjoint_anchors_arc(),
21668                        self.selections.line_mode(),
21669                        self.cursor_shape,
21670                        cx,
21671                    );
21672                }
21673            });
21674        }
21675    }
21676
21677    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21678        cx.emit(EditorEvent::FocusedIn)
21679    }
21680
21681    fn handle_focus_out(
21682        &mut self,
21683        event: FocusOutEvent,
21684        _window: &mut Window,
21685        cx: &mut Context<Self>,
21686    ) {
21687        if event.blurred != self.focus_handle {
21688            self.last_focused_descendant = Some(event.blurred);
21689        }
21690        self.selection_drag_state = SelectionDragState::None;
21691        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21692    }
21693
21694    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21695        self.blink_manager.update(cx, BlinkManager::disable);
21696        self.buffer
21697            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21698
21699        if let Some(blame) = self.blame.as_ref() {
21700            blame.update(cx, GitBlame::blur)
21701        }
21702        if !self.hover_state.focused(window, cx) {
21703            hide_hover(self, cx);
21704        }
21705        if !self
21706            .context_menu
21707            .borrow()
21708            .as_ref()
21709            .is_some_and(|context_menu| context_menu.focused(window, cx))
21710        {
21711            self.hide_context_menu(window, cx);
21712        }
21713        self.take_active_edit_prediction(cx);
21714        cx.emit(EditorEvent::Blurred);
21715        cx.notify();
21716    }
21717
21718    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21719        let mut pending: String = window
21720            .pending_input_keystrokes()
21721            .into_iter()
21722            .flatten()
21723            .filter_map(|keystroke| {
21724                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21725                    keystroke.key_char.clone()
21726                } else {
21727                    None
21728                }
21729            })
21730            .collect();
21731
21732        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21733            pending = "".to_string();
21734        }
21735
21736        let existing_pending = self
21737            .text_highlights::<PendingInput>(cx)
21738            .map(|(_, ranges)| ranges.to_vec());
21739        if existing_pending.is_none() && pending.is_empty() {
21740            return;
21741        }
21742        let transaction =
21743            self.transact(window, cx, |this, window, cx| {
21744                let selections = this.selections.all::<usize>(cx);
21745                let edits = selections
21746                    .iter()
21747                    .map(|selection| (selection.end..selection.end, pending.clone()));
21748                this.edit(edits, cx);
21749                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21750                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21751                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21752                    }));
21753                });
21754                if let Some(existing_ranges) = existing_pending {
21755                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21756                    this.edit(edits, cx);
21757                }
21758            });
21759
21760        let snapshot = self.snapshot(window, cx);
21761        let ranges = self
21762            .selections
21763            .all::<usize>(cx)
21764            .into_iter()
21765            .map(|selection| {
21766                snapshot.buffer_snapshot().anchor_after(selection.end)
21767                    ..snapshot
21768                        .buffer_snapshot()
21769                        .anchor_before(selection.end + pending.len())
21770            })
21771            .collect();
21772
21773        if pending.is_empty() {
21774            self.clear_highlights::<PendingInput>(cx);
21775        } else {
21776            self.highlight_text::<PendingInput>(
21777                ranges,
21778                HighlightStyle {
21779                    underline: Some(UnderlineStyle {
21780                        thickness: px(1.),
21781                        color: None,
21782                        wavy: false,
21783                    }),
21784                    ..Default::default()
21785                },
21786                cx,
21787            );
21788        }
21789
21790        self.ime_transaction = self.ime_transaction.or(transaction);
21791        if let Some(transaction) = self.ime_transaction {
21792            self.buffer.update(cx, |buffer, cx| {
21793                buffer.group_until_transaction(transaction, cx);
21794            });
21795        }
21796
21797        if self.text_highlights::<PendingInput>(cx).is_none() {
21798            self.ime_transaction.take();
21799        }
21800    }
21801
21802    pub fn register_action_renderer(
21803        &mut self,
21804        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21805    ) -> Subscription {
21806        let id = self.next_editor_action_id.post_inc();
21807        self.editor_actions
21808            .borrow_mut()
21809            .insert(id, Box::new(listener));
21810
21811        let editor_actions = self.editor_actions.clone();
21812        Subscription::new(move || {
21813            editor_actions.borrow_mut().remove(&id);
21814        })
21815    }
21816
21817    pub fn register_action<A: Action>(
21818        &mut self,
21819        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21820    ) -> Subscription {
21821        let id = self.next_editor_action_id.post_inc();
21822        let listener = Arc::new(listener);
21823        self.editor_actions.borrow_mut().insert(
21824            id,
21825            Box::new(move |_, window, _| {
21826                let listener = listener.clone();
21827                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21828                    let action = action.downcast_ref().unwrap();
21829                    if phase == DispatchPhase::Bubble {
21830                        listener(action, window, cx)
21831                    }
21832                })
21833            }),
21834        );
21835
21836        let editor_actions = self.editor_actions.clone();
21837        Subscription::new(move || {
21838            editor_actions.borrow_mut().remove(&id);
21839        })
21840    }
21841
21842    pub fn file_header_size(&self) -> u32 {
21843        FILE_HEADER_HEIGHT
21844    }
21845
21846    pub fn restore(
21847        &mut self,
21848        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21849        window: &mut Window,
21850        cx: &mut Context<Self>,
21851    ) {
21852        let workspace = self.workspace();
21853        let project = self.project();
21854        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21855            let mut tasks = Vec::new();
21856            for (buffer_id, changes) in revert_changes {
21857                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21858                    buffer.update(cx, |buffer, cx| {
21859                        buffer.edit(
21860                            changes
21861                                .into_iter()
21862                                .map(|(range, text)| (range, text.to_string())),
21863                            None,
21864                            cx,
21865                        );
21866                    });
21867
21868                    if let Some(project) =
21869                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21870                    {
21871                        project.update(cx, |project, cx| {
21872                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21873                        })
21874                    }
21875                }
21876            }
21877            tasks
21878        });
21879        cx.spawn_in(window, async move |_, cx| {
21880            for (buffer, task) in save_tasks {
21881                let result = task.await;
21882                if result.is_err() {
21883                    let Some(path) = buffer
21884                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21885                        .ok()
21886                    else {
21887                        continue;
21888                    };
21889                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21890                        let Some(task) = cx
21891                            .update_window_entity(workspace, |workspace, window, cx| {
21892                                workspace
21893                                    .open_path_preview(path, None, false, false, false, window, cx)
21894                            })
21895                            .ok()
21896                        else {
21897                            continue;
21898                        };
21899                        task.await.log_err();
21900                    }
21901                }
21902            }
21903        })
21904        .detach();
21905        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21906            selections.refresh()
21907        });
21908    }
21909
21910    pub fn to_pixel_point(
21911        &self,
21912        source: multi_buffer::Anchor,
21913        editor_snapshot: &EditorSnapshot,
21914        window: &mut Window,
21915    ) -> Option<gpui::Point<Pixels>> {
21916        let source_point = source.to_display_point(editor_snapshot);
21917        self.display_to_pixel_point(source_point, editor_snapshot, window)
21918    }
21919
21920    pub fn display_to_pixel_point(
21921        &self,
21922        source: DisplayPoint,
21923        editor_snapshot: &EditorSnapshot,
21924        window: &mut Window,
21925    ) -> Option<gpui::Point<Pixels>> {
21926        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21927        let text_layout_details = self.text_layout_details(window);
21928        let scroll_top = text_layout_details
21929            .scroll_anchor
21930            .scroll_position(editor_snapshot)
21931            .y;
21932
21933        if source.row().as_f64() < scroll_top.floor() {
21934            return None;
21935        }
21936        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21937        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21938        Some(gpui::Point::new(source_x, source_y))
21939    }
21940
21941    pub fn has_visible_completions_menu(&self) -> bool {
21942        !self.edit_prediction_preview_is_active()
21943            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21944                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21945            })
21946    }
21947
21948    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21949        if self.mode.is_minimap() {
21950            return;
21951        }
21952        self.addons
21953            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21954    }
21955
21956    pub fn unregister_addon<T: Addon>(&mut self) {
21957        self.addons.remove(&std::any::TypeId::of::<T>());
21958    }
21959
21960    pub fn addon<T: Addon>(&self) -> Option<&T> {
21961        let type_id = std::any::TypeId::of::<T>();
21962        self.addons
21963            .get(&type_id)
21964            .and_then(|item| item.to_any().downcast_ref::<T>())
21965    }
21966
21967    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21968        let type_id = std::any::TypeId::of::<T>();
21969        self.addons
21970            .get_mut(&type_id)
21971            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21972    }
21973
21974    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21975        let text_layout_details = self.text_layout_details(window);
21976        let style = &text_layout_details.editor_style;
21977        let font_id = window.text_system().resolve_font(&style.text.font());
21978        let font_size = style.text.font_size.to_pixels(window.rem_size());
21979        let line_height = style.text.line_height_in_pixels(window.rem_size());
21980        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21981        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21982
21983        CharacterDimensions {
21984            em_width,
21985            em_advance,
21986            line_height,
21987        }
21988    }
21989
21990    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21991        self.load_diff_task.clone()
21992    }
21993
21994    fn read_metadata_from_db(
21995        &mut self,
21996        item_id: u64,
21997        workspace_id: WorkspaceId,
21998        window: &mut Window,
21999        cx: &mut Context<Editor>,
22000    ) {
22001        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22002            && !self.mode.is_minimap()
22003            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22004        {
22005            let buffer_snapshot = OnceCell::new();
22006
22007            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22008                && !folds.is_empty()
22009            {
22010                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22011                self.fold_ranges(
22012                    folds
22013                        .into_iter()
22014                        .map(|(start, end)| {
22015                            snapshot.clip_offset(start, Bias::Left)
22016                                ..snapshot.clip_offset(end, Bias::Right)
22017                        })
22018                        .collect(),
22019                    false,
22020                    window,
22021                    cx,
22022                );
22023            }
22024
22025            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22026                && !selections.is_empty()
22027            {
22028                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22029                // skip adding the initial selection to selection history
22030                self.selection_history.mode = SelectionHistoryMode::Skipping;
22031                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22032                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22033                        snapshot.clip_offset(start, Bias::Left)
22034                            ..snapshot.clip_offset(end, Bias::Right)
22035                    }));
22036                });
22037                self.selection_history.mode = SelectionHistoryMode::Normal;
22038            };
22039        }
22040
22041        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22042    }
22043
22044    fn update_lsp_data(
22045        &mut self,
22046        ignore_cache: bool,
22047        for_buffer: Option<BufferId>,
22048        window: &mut Window,
22049        cx: &mut Context<'_, Self>,
22050    ) {
22051        self.pull_diagnostics(for_buffer, window, cx);
22052        self.refresh_colors(ignore_cache, for_buffer, window, cx);
22053    }
22054}
22055
22056fn edit_for_markdown_paste<'a>(
22057    buffer: &MultiBufferSnapshot,
22058    range: Range<usize>,
22059    to_insert: &'a str,
22060    url: Option<url::Url>,
22061) -> (Range<usize>, Cow<'a, str>) {
22062    if url.is_none() {
22063        return (range, Cow::Borrowed(to_insert));
22064    };
22065
22066    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22067
22068    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22069        Cow::Borrowed(to_insert)
22070    } else {
22071        Cow::Owned(format!("[{old_text}]({to_insert})"))
22072    };
22073    (range, new_text)
22074}
22075
22076fn vim_enabled(cx: &App) -> bool {
22077    vim_mode_setting::VimModeSetting::try_get(cx)
22078        .map(|vim_mode| vim_mode.0)
22079        .unwrap_or(false)
22080}
22081
22082fn process_completion_for_edit(
22083    completion: &Completion,
22084    intent: CompletionIntent,
22085    buffer: &Entity<Buffer>,
22086    cursor_position: &text::Anchor,
22087    cx: &mut Context<Editor>,
22088) -> CompletionEdit {
22089    let buffer = buffer.read(cx);
22090    let buffer_snapshot = buffer.snapshot();
22091    let (snippet, new_text) = if completion.is_snippet() {
22092        let mut snippet_source = completion.new_text.clone();
22093        // Workaround for typescript language server issues so that methods don't expand within
22094        // strings and functions with type expressions. The previous point is used because the query
22095        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22096        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22097        let previous_point = if previous_point.column > 0 {
22098            cursor_position.to_previous_offset(&buffer_snapshot)
22099        } else {
22100            cursor_position.to_offset(&buffer_snapshot)
22101        };
22102        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22103            && scope.prefers_label_for_snippet_in_completion()
22104            && let Some(label) = completion.label()
22105            && matches!(
22106                completion.kind(),
22107                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22108            )
22109        {
22110            snippet_source = label;
22111        }
22112        match Snippet::parse(&snippet_source).log_err() {
22113            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22114            None => (None, completion.new_text.clone()),
22115        }
22116    } else {
22117        (None, completion.new_text.clone())
22118    };
22119
22120    let mut range_to_replace = {
22121        let replace_range = &completion.replace_range;
22122        if let CompletionSource::Lsp {
22123            insert_range: Some(insert_range),
22124            ..
22125        } = &completion.source
22126        {
22127            debug_assert_eq!(
22128                insert_range.start, replace_range.start,
22129                "insert_range and replace_range should start at the same position"
22130            );
22131            debug_assert!(
22132                insert_range
22133                    .start
22134                    .cmp(cursor_position, &buffer_snapshot)
22135                    .is_le(),
22136                "insert_range should start before or at cursor position"
22137            );
22138            debug_assert!(
22139                replace_range
22140                    .start
22141                    .cmp(cursor_position, &buffer_snapshot)
22142                    .is_le(),
22143                "replace_range should start before or at cursor position"
22144            );
22145
22146            let should_replace = match intent {
22147                CompletionIntent::CompleteWithInsert => false,
22148                CompletionIntent::CompleteWithReplace => true,
22149                CompletionIntent::Complete | CompletionIntent::Compose => {
22150                    let insert_mode =
22151                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22152                            .completions
22153                            .lsp_insert_mode;
22154                    match insert_mode {
22155                        LspInsertMode::Insert => false,
22156                        LspInsertMode::Replace => true,
22157                        LspInsertMode::ReplaceSubsequence => {
22158                            let mut text_to_replace = buffer.chars_for_range(
22159                                buffer.anchor_before(replace_range.start)
22160                                    ..buffer.anchor_after(replace_range.end),
22161                            );
22162                            let mut current_needle = text_to_replace.next();
22163                            for haystack_ch in completion.label.text.chars() {
22164                                if let Some(needle_ch) = current_needle
22165                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22166                                {
22167                                    current_needle = text_to_replace.next();
22168                                }
22169                            }
22170                            current_needle.is_none()
22171                        }
22172                        LspInsertMode::ReplaceSuffix => {
22173                            if replace_range
22174                                .end
22175                                .cmp(cursor_position, &buffer_snapshot)
22176                                .is_gt()
22177                            {
22178                                let range_after_cursor = *cursor_position..replace_range.end;
22179                                let text_after_cursor = buffer
22180                                    .text_for_range(
22181                                        buffer.anchor_before(range_after_cursor.start)
22182                                            ..buffer.anchor_after(range_after_cursor.end),
22183                                    )
22184                                    .collect::<String>()
22185                                    .to_ascii_lowercase();
22186                                completion
22187                                    .label
22188                                    .text
22189                                    .to_ascii_lowercase()
22190                                    .ends_with(&text_after_cursor)
22191                            } else {
22192                                true
22193                            }
22194                        }
22195                    }
22196                }
22197            };
22198
22199            if should_replace {
22200                replace_range.clone()
22201            } else {
22202                insert_range.clone()
22203            }
22204        } else {
22205            replace_range.clone()
22206        }
22207    };
22208
22209    if range_to_replace
22210        .end
22211        .cmp(cursor_position, &buffer_snapshot)
22212        .is_lt()
22213    {
22214        range_to_replace.end = *cursor_position;
22215    }
22216
22217    CompletionEdit {
22218        new_text,
22219        replace_range: range_to_replace.to_offset(buffer),
22220        snippet,
22221    }
22222}
22223
22224struct CompletionEdit {
22225    new_text: String,
22226    replace_range: Range<usize>,
22227    snippet: Option<Snippet>,
22228}
22229
22230fn insert_extra_newline_brackets(
22231    buffer: &MultiBufferSnapshot,
22232    range: Range<usize>,
22233    language: &language::LanguageScope,
22234) -> bool {
22235    let leading_whitespace_len = buffer
22236        .reversed_chars_at(range.start)
22237        .take_while(|c| c.is_whitespace() && *c != '\n')
22238        .map(|c| c.len_utf8())
22239        .sum::<usize>();
22240    let trailing_whitespace_len = buffer
22241        .chars_at(range.end)
22242        .take_while(|c| c.is_whitespace() && *c != '\n')
22243        .map(|c| c.len_utf8())
22244        .sum::<usize>();
22245    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22246
22247    language.brackets().any(|(pair, enabled)| {
22248        let pair_start = pair.start.trim_end();
22249        let pair_end = pair.end.trim_start();
22250
22251        enabled
22252            && pair.newline
22253            && buffer.contains_str_at(range.end, pair_end)
22254            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22255    })
22256}
22257
22258fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22259    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22260        [(buffer, range, _)] => (*buffer, range.clone()),
22261        _ => return false,
22262    };
22263    let pair = {
22264        let mut result: Option<BracketMatch> = None;
22265
22266        for pair in buffer
22267            .all_bracket_ranges(range.clone())
22268            .filter(move |pair| {
22269                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22270            })
22271        {
22272            let len = pair.close_range.end - pair.open_range.start;
22273
22274            if let Some(existing) = &result {
22275                let existing_len = existing.close_range.end - existing.open_range.start;
22276                if len > existing_len {
22277                    continue;
22278                }
22279            }
22280
22281            result = Some(pair);
22282        }
22283
22284        result
22285    };
22286    let Some(pair) = pair else {
22287        return false;
22288    };
22289    pair.newline_only
22290        && buffer
22291            .chars_for_range(pair.open_range.end..range.start)
22292            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22293            .all(|c| c.is_whitespace() && c != '\n')
22294}
22295
22296fn update_uncommitted_diff_for_buffer(
22297    editor: Entity<Editor>,
22298    project: &Entity<Project>,
22299    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22300    buffer: Entity<MultiBuffer>,
22301    cx: &mut App,
22302) -> Task<()> {
22303    let mut tasks = Vec::new();
22304    project.update(cx, |project, cx| {
22305        for buffer in buffers {
22306            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22307                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22308            }
22309        }
22310    });
22311    cx.spawn(async move |cx| {
22312        let diffs = future::join_all(tasks).await;
22313        if editor
22314            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22315            .unwrap_or(false)
22316        {
22317            return;
22318        }
22319
22320        buffer
22321            .update(cx, |buffer, cx| {
22322                for diff in diffs.into_iter().flatten() {
22323                    buffer.add_diff(diff, cx);
22324                }
22325            })
22326            .ok();
22327    })
22328}
22329
22330fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22331    let tab_size = tab_size.get() as usize;
22332    let mut width = offset;
22333
22334    for ch in text.chars() {
22335        width += if ch == '\t' {
22336            tab_size - (width % tab_size)
22337        } else {
22338            1
22339        };
22340    }
22341
22342    width - offset
22343}
22344
22345#[cfg(test)]
22346mod tests {
22347    use super::*;
22348
22349    #[test]
22350    fn test_string_size_with_expanded_tabs() {
22351        let nz = |val| NonZeroU32::new(val).unwrap();
22352        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22353        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22354        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22355        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22356        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22357        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22358        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22359        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22360    }
22361}
22362
22363/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22364struct WordBreakingTokenizer<'a> {
22365    input: &'a str,
22366}
22367
22368impl<'a> WordBreakingTokenizer<'a> {
22369    fn new(input: &'a str) -> Self {
22370        Self { input }
22371    }
22372}
22373
22374fn is_char_ideographic(ch: char) -> bool {
22375    use unicode_script::Script::*;
22376    use unicode_script::UnicodeScript;
22377    matches!(ch.script(), Han | Tangut | Yi)
22378}
22379
22380fn is_grapheme_ideographic(text: &str) -> bool {
22381    text.chars().any(is_char_ideographic)
22382}
22383
22384fn is_grapheme_whitespace(text: &str) -> bool {
22385    text.chars().any(|x| x.is_whitespace())
22386}
22387
22388fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22389    text.chars()
22390        .next()
22391        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22392}
22393
22394#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22395enum WordBreakToken<'a> {
22396    Word { token: &'a str, grapheme_len: usize },
22397    InlineWhitespace { token: &'a str, grapheme_len: usize },
22398    Newline,
22399}
22400
22401impl<'a> Iterator for WordBreakingTokenizer<'a> {
22402    /// Yields a span, the count of graphemes in the token, and whether it was
22403    /// whitespace. Note that it also breaks at word boundaries.
22404    type Item = WordBreakToken<'a>;
22405
22406    fn next(&mut self) -> Option<Self::Item> {
22407        use unicode_segmentation::UnicodeSegmentation;
22408        if self.input.is_empty() {
22409            return None;
22410        }
22411
22412        let mut iter = self.input.graphemes(true).peekable();
22413        let mut offset = 0;
22414        let mut grapheme_len = 0;
22415        if let Some(first_grapheme) = iter.next() {
22416            let is_newline = first_grapheme == "\n";
22417            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22418            offset += first_grapheme.len();
22419            grapheme_len += 1;
22420            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22421                if let Some(grapheme) = iter.peek().copied()
22422                    && should_stay_with_preceding_ideograph(grapheme)
22423                {
22424                    offset += grapheme.len();
22425                    grapheme_len += 1;
22426                }
22427            } else {
22428                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22429                let mut next_word_bound = words.peek().copied();
22430                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22431                    next_word_bound = words.next();
22432                }
22433                while let Some(grapheme) = iter.peek().copied() {
22434                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22435                        break;
22436                    };
22437                    if is_grapheme_whitespace(grapheme) != is_whitespace
22438                        || (grapheme == "\n") != is_newline
22439                    {
22440                        break;
22441                    };
22442                    offset += grapheme.len();
22443                    grapheme_len += 1;
22444                    iter.next();
22445                }
22446            }
22447            let token = &self.input[..offset];
22448            self.input = &self.input[offset..];
22449            if token == "\n" {
22450                Some(WordBreakToken::Newline)
22451            } else if is_whitespace {
22452                Some(WordBreakToken::InlineWhitespace {
22453                    token,
22454                    grapheme_len,
22455                })
22456            } else {
22457                Some(WordBreakToken::Word {
22458                    token,
22459                    grapheme_len,
22460                })
22461            }
22462        } else {
22463            None
22464        }
22465    }
22466}
22467
22468#[test]
22469fn test_word_breaking_tokenizer() {
22470    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22471        ("", &[]),
22472        ("  ", &[whitespace("  ", 2)]),
22473        ("Ʒ", &[word("Ʒ", 1)]),
22474        ("Ǽ", &[word("Ǽ", 1)]),
22475        ("", &[word("", 1)]),
22476        ("⋑⋑", &[word("⋑⋑", 2)]),
22477        (
22478            "原理,进而",
22479            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22480        ),
22481        (
22482            "hello world",
22483            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22484        ),
22485        (
22486            "hello, world",
22487            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22488        ),
22489        (
22490            "  hello world",
22491            &[
22492                whitespace("  ", 2),
22493                word("hello", 5),
22494                whitespace(" ", 1),
22495                word("world", 5),
22496            ],
22497        ),
22498        (
22499            "这是什么 \n 钢笔",
22500            &[
22501                word("", 1),
22502                word("", 1),
22503                word("", 1),
22504                word("", 1),
22505                whitespace(" ", 1),
22506                newline(),
22507                whitespace(" ", 1),
22508                word("", 1),
22509                word("", 1),
22510            ],
22511        ),
22512        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22513    ];
22514
22515    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22516        WordBreakToken::Word {
22517            token,
22518            grapheme_len,
22519        }
22520    }
22521
22522    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22523        WordBreakToken::InlineWhitespace {
22524            token,
22525            grapheme_len,
22526        }
22527    }
22528
22529    fn newline() -> WordBreakToken<'static> {
22530        WordBreakToken::Newline
22531    }
22532
22533    for (input, result) in tests {
22534        assert_eq!(
22535            WordBreakingTokenizer::new(input)
22536                .collect::<Vec<_>>()
22537                .as_slice(),
22538            *result,
22539        );
22540    }
22541}
22542
22543fn wrap_with_prefix(
22544    first_line_prefix: String,
22545    subsequent_lines_prefix: String,
22546    unwrapped_text: String,
22547    wrap_column: usize,
22548    tab_size: NonZeroU32,
22549    preserve_existing_whitespace: bool,
22550) -> String {
22551    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22552    let subsequent_lines_prefix_len =
22553        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22554    let mut wrapped_text = String::new();
22555    let mut current_line = first_line_prefix;
22556    let mut is_first_line = true;
22557
22558    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22559    let mut current_line_len = first_line_prefix_len;
22560    let mut in_whitespace = false;
22561    for token in tokenizer {
22562        let have_preceding_whitespace = in_whitespace;
22563        match token {
22564            WordBreakToken::Word {
22565                token,
22566                grapheme_len,
22567            } => {
22568                in_whitespace = false;
22569                let current_prefix_len = if is_first_line {
22570                    first_line_prefix_len
22571                } else {
22572                    subsequent_lines_prefix_len
22573                };
22574                if current_line_len + grapheme_len > wrap_column
22575                    && current_line_len != current_prefix_len
22576                {
22577                    wrapped_text.push_str(current_line.trim_end());
22578                    wrapped_text.push('\n');
22579                    is_first_line = false;
22580                    current_line = subsequent_lines_prefix.clone();
22581                    current_line_len = subsequent_lines_prefix_len;
22582                }
22583                current_line.push_str(token);
22584                current_line_len += grapheme_len;
22585            }
22586            WordBreakToken::InlineWhitespace {
22587                mut token,
22588                mut grapheme_len,
22589            } => {
22590                in_whitespace = true;
22591                if have_preceding_whitespace && !preserve_existing_whitespace {
22592                    continue;
22593                }
22594                if !preserve_existing_whitespace {
22595                    // Keep a single whitespace grapheme as-is
22596                    if let Some(first) =
22597                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22598                    {
22599                        token = first;
22600                    } else {
22601                        token = " ";
22602                    }
22603                    grapheme_len = 1;
22604                }
22605                let current_prefix_len = if is_first_line {
22606                    first_line_prefix_len
22607                } else {
22608                    subsequent_lines_prefix_len
22609                };
22610                if current_line_len + grapheme_len > wrap_column {
22611                    wrapped_text.push_str(current_line.trim_end());
22612                    wrapped_text.push('\n');
22613                    is_first_line = false;
22614                    current_line = subsequent_lines_prefix.clone();
22615                    current_line_len = subsequent_lines_prefix_len;
22616                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22617                    current_line.push_str(token);
22618                    current_line_len += grapheme_len;
22619                }
22620            }
22621            WordBreakToken::Newline => {
22622                in_whitespace = true;
22623                let current_prefix_len = if is_first_line {
22624                    first_line_prefix_len
22625                } else {
22626                    subsequent_lines_prefix_len
22627                };
22628                if preserve_existing_whitespace {
22629                    wrapped_text.push_str(current_line.trim_end());
22630                    wrapped_text.push('\n');
22631                    is_first_line = false;
22632                    current_line = subsequent_lines_prefix.clone();
22633                    current_line_len = subsequent_lines_prefix_len;
22634                } else if have_preceding_whitespace {
22635                    continue;
22636                } else if current_line_len + 1 > wrap_column
22637                    && current_line_len != current_prefix_len
22638                {
22639                    wrapped_text.push_str(current_line.trim_end());
22640                    wrapped_text.push('\n');
22641                    is_first_line = false;
22642                    current_line = subsequent_lines_prefix.clone();
22643                    current_line_len = subsequent_lines_prefix_len;
22644                } else if current_line_len != current_prefix_len {
22645                    current_line.push(' ');
22646                    current_line_len += 1;
22647                }
22648            }
22649        }
22650    }
22651
22652    if !current_line.is_empty() {
22653        wrapped_text.push_str(&current_line);
22654    }
22655    wrapped_text
22656}
22657
22658#[test]
22659fn test_wrap_with_prefix() {
22660    assert_eq!(
22661        wrap_with_prefix(
22662            "# ".to_string(),
22663            "# ".to_string(),
22664            "abcdefg".to_string(),
22665            4,
22666            NonZeroU32::new(4).unwrap(),
22667            false,
22668        ),
22669        "# abcdefg"
22670    );
22671    assert_eq!(
22672        wrap_with_prefix(
22673            "".to_string(),
22674            "".to_string(),
22675            "\thello world".to_string(),
22676            8,
22677            NonZeroU32::new(4).unwrap(),
22678            false,
22679        ),
22680        "hello\nworld"
22681    );
22682    assert_eq!(
22683        wrap_with_prefix(
22684            "// ".to_string(),
22685            "// ".to_string(),
22686            "xx \nyy zz aa bb cc".to_string(),
22687            12,
22688            NonZeroU32::new(4).unwrap(),
22689            false,
22690        ),
22691        "// xx yy zz\n// aa bb cc"
22692    );
22693    assert_eq!(
22694        wrap_with_prefix(
22695            String::new(),
22696            String::new(),
22697            "这是什么 \n 钢笔".to_string(),
22698            3,
22699            NonZeroU32::new(4).unwrap(),
22700            false,
22701        ),
22702        "这是什\n么 钢\n"
22703    );
22704    assert_eq!(
22705        wrap_with_prefix(
22706            String::new(),
22707            String::new(),
22708            format!("foo{}bar", '\u{2009}'), // thin space
22709            80,
22710            NonZeroU32::new(4).unwrap(),
22711            false,
22712        ),
22713        format!("foo{}bar", '\u{2009}')
22714    );
22715}
22716
22717pub trait CollaborationHub {
22718    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22719    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22720    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22721}
22722
22723impl CollaborationHub for Entity<Project> {
22724    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22725        self.read(cx).collaborators()
22726    }
22727
22728    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22729        self.read(cx).user_store().read(cx).participant_indices()
22730    }
22731
22732    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22733        let this = self.read(cx);
22734        let user_ids = this.collaborators().values().map(|c| c.user_id);
22735        this.user_store().read(cx).participant_names(user_ids, cx)
22736    }
22737}
22738
22739pub trait SemanticsProvider {
22740    fn hover(
22741        &self,
22742        buffer: &Entity<Buffer>,
22743        position: text::Anchor,
22744        cx: &mut App,
22745    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22746
22747    fn inline_values(
22748        &self,
22749        buffer_handle: Entity<Buffer>,
22750        range: Range<text::Anchor>,
22751        cx: &mut App,
22752    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22753
22754    fn inlay_hints(
22755        &self,
22756        buffer_handle: Entity<Buffer>,
22757        range: Range<text::Anchor>,
22758        cx: &mut App,
22759    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22760
22761    fn resolve_inlay_hint(
22762        &self,
22763        hint: InlayHint,
22764        buffer_handle: Entity<Buffer>,
22765        server_id: LanguageServerId,
22766        cx: &mut App,
22767    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22768
22769    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22770
22771    fn document_highlights(
22772        &self,
22773        buffer: &Entity<Buffer>,
22774        position: text::Anchor,
22775        cx: &mut App,
22776    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22777
22778    fn definitions(
22779        &self,
22780        buffer: &Entity<Buffer>,
22781        position: text::Anchor,
22782        kind: GotoDefinitionKind,
22783        cx: &mut App,
22784    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22785
22786    fn range_for_rename(
22787        &self,
22788        buffer: &Entity<Buffer>,
22789        position: text::Anchor,
22790        cx: &mut App,
22791    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22792
22793    fn perform_rename(
22794        &self,
22795        buffer: &Entity<Buffer>,
22796        position: text::Anchor,
22797        new_name: String,
22798        cx: &mut App,
22799    ) -> Option<Task<Result<ProjectTransaction>>>;
22800}
22801
22802pub trait CompletionProvider {
22803    fn completions(
22804        &self,
22805        excerpt_id: ExcerptId,
22806        buffer: &Entity<Buffer>,
22807        buffer_position: text::Anchor,
22808        trigger: CompletionContext,
22809        window: &mut Window,
22810        cx: &mut Context<Editor>,
22811    ) -> Task<Result<Vec<CompletionResponse>>>;
22812
22813    fn resolve_completions(
22814        &self,
22815        _buffer: Entity<Buffer>,
22816        _completion_indices: Vec<usize>,
22817        _completions: Rc<RefCell<Box<[Completion]>>>,
22818        _cx: &mut Context<Editor>,
22819    ) -> Task<Result<bool>> {
22820        Task::ready(Ok(false))
22821    }
22822
22823    fn apply_additional_edits_for_completion(
22824        &self,
22825        _buffer: Entity<Buffer>,
22826        _completions: Rc<RefCell<Box<[Completion]>>>,
22827        _completion_index: usize,
22828        _push_to_history: bool,
22829        _cx: &mut Context<Editor>,
22830    ) -> Task<Result<Option<language::Transaction>>> {
22831        Task::ready(Ok(None))
22832    }
22833
22834    fn is_completion_trigger(
22835        &self,
22836        buffer: &Entity<Buffer>,
22837        position: language::Anchor,
22838        text: &str,
22839        trigger_in_words: bool,
22840        menu_is_open: bool,
22841        cx: &mut Context<Editor>,
22842    ) -> bool;
22843
22844    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22845
22846    fn sort_completions(&self) -> bool {
22847        true
22848    }
22849
22850    fn filter_completions(&self) -> bool {
22851        true
22852    }
22853}
22854
22855pub trait CodeActionProvider {
22856    fn id(&self) -> Arc<str>;
22857
22858    fn code_actions(
22859        &self,
22860        buffer: &Entity<Buffer>,
22861        range: Range<text::Anchor>,
22862        window: &mut Window,
22863        cx: &mut App,
22864    ) -> Task<Result<Vec<CodeAction>>>;
22865
22866    fn apply_code_action(
22867        &self,
22868        buffer_handle: Entity<Buffer>,
22869        action: CodeAction,
22870        excerpt_id: ExcerptId,
22871        push_to_history: bool,
22872        window: &mut Window,
22873        cx: &mut App,
22874    ) -> Task<Result<ProjectTransaction>>;
22875}
22876
22877impl CodeActionProvider for Entity<Project> {
22878    fn id(&self) -> Arc<str> {
22879        "project".into()
22880    }
22881
22882    fn code_actions(
22883        &self,
22884        buffer: &Entity<Buffer>,
22885        range: Range<text::Anchor>,
22886        _window: &mut Window,
22887        cx: &mut App,
22888    ) -> Task<Result<Vec<CodeAction>>> {
22889        self.update(cx, |project, cx| {
22890            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22891            let code_actions = project.code_actions(buffer, range, None, cx);
22892            cx.background_spawn(async move {
22893                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22894                Ok(code_lens_actions
22895                    .context("code lens fetch")?
22896                    .into_iter()
22897                    .flatten()
22898                    .chain(
22899                        code_actions
22900                            .context("code action fetch")?
22901                            .into_iter()
22902                            .flatten(),
22903                    )
22904                    .collect())
22905            })
22906        })
22907    }
22908
22909    fn apply_code_action(
22910        &self,
22911        buffer_handle: Entity<Buffer>,
22912        action: CodeAction,
22913        _excerpt_id: ExcerptId,
22914        push_to_history: bool,
22915        _window: &mut Window,
22916        cx: &mut App,
22917    ) -> Task<Result<ProjectTransaction>> {
22918        self.update(cx, |project, cx| {
22919            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22920        })
22921    }
22922}
22923
22924fn snippet_completions(
22925    project: &Project,
22926    buffer: &Entity<Buffer>,
22927    buffer_position: text::Anchor,
22928    cx: &mut App,
22929) -> Task<Result<CompletionResponse>> {
22930    let languages = buffer.read(cx).languages_at(buffer_position);
22931    let snippet_store = project.snippets().read(cx);
22932
22933    let scopes: Vec<_> = languages
22934        .iter()
22935        .filter_map(|language| {
22936            let language_name = language.lsp_id();
22937            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22938
22939            if snippets.is_empty() {
22940                None
22941            } else {
22942                Some((language.default_scope(), snippets))
22943            }
22944        })
22945        .collect();
22946
22947    if scopes.is_empty() {
22948        return Task::ready(Ok(CompletionResponse {
22949            completions: vec![],
22950            display_options: CompletionDisplayOptions::default(),
22951            is_incomplete: false,
22952        }));
22953    }
22954
22955    let snapshot = buffer.read(cx).text_snapshot();
22956    let executor = cx.background_executor().clone();
22957
22958    cx.background_spawn(async move {
22959        let mut is_incomplete = false;
22960        let mut completions: Vec<Completion> = Vec::new();
22961        for (scope, snippets) in scopes.into_iter() {
22962            let classifier =
22963                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22964
22965            const MAX_WORD_PREFIX_LEN: usize = 128;
22966            let last_word: String = snapshot
22967                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22968                .take(MAX_WORD_PREFIX_LEN)
22969                .take_while(|c| classifier.is_word(*c))
22970                .collect::<String>()
22971                .chars()
22972                .rev()
22973                .collect();
22974
22975            if last_word.is_empty() {
22976                return Ok(CompletionResponse {
22977                    completions: vec![],
22978                    display_options: CompletionDisplayOptions::default(),
22979                    is_incomplete: true,
22980                });
22981            }
22982
22983            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22984            let to_lsp = |point: &text::Anchor| {
22985                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22986                point_to_lsp(end)
22987            };
22988            let lsp_end = to_lsp(&buffer_position);
22989
22990            let candidates = snippets
22991                .iter()
22992                .enumerate()
22993                .flat_map(|(ix, snippet)| {
22994                    snippet
22995                        .prefix
22996                        .iter()
22997                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22998                })
22999                .collect::<Vec<StringMatchCandidate>>();
23000
23001            const MAX_RESULTS: usize = 100;
23002            let mut matches = fuzzy::match_strings(
23003                &candidates,
23004                &last_word,
23005                last_word.chars().any(|c| c.is_uppercase()),
23006                true,
23007                MAX_RESULTS,
23008                &Default::default(),
23009                executor.clone(),
23010            )
23011            .await;
23012
23013            if matches.len() >= MAX_RESULTS {
23014                is_incomplete = true;
23015            }
23016
23017            // Remove all candidates where the query's start does not match the start of any word in the candidate
23018            if let Some(query_start) = last_word.chars().next() {
23019                matches.retain(|string_match| {
23020                    split_words(&string_match.string).any(|word| {
23021                        // Check that the first codepoint of the word as lowercase matches the first
23022                        // codepoint of the query as lowercase
23023                        word.chars()
23024                            .flat_map(|codepoint| codepoint.to_lowercase())
23025                            .zip(query_start.to_lowercase())
23026                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23027                    })
23028                });
23029            }
23030
23031            let matched_strings = matches
23032                .into_iter()
23033                .map(|m| m.string)
23034                .collect::<HashSet<_>>();
23035
23036            completions.extend(snippets.iter().filter_map(|snippet| {
23037                let matching_prefix = snippet
23038                    .prefix
23039                    .iter()
23040                    .find(|prefix| matched_strings.contains(*prefix))?;
23041                let start = as_offset - last_word.len();
23042                let start = snapshot.anchor_before(start);
23043                let range = start..buffer_position;
23044                let lsp_start = to_lsp(&start);
23045                let lsp_range = lsp::Range {
23046                    start: lsp_start,
23047                    end: lsp_end,
23048                };
23049                Some(Completion {
23050                    replace_range: range,
23051                    new_text: snippet.body.clone(),
23052                    source: CompletionSource::Lsp {
23053                        insert_range: None,
23054                        server_id: LanguageServerId(usize::MAX),
23055                        resolved: true,
23056                        lsp_completion: Box::new(lsp::CompletionItem {
23057                            label: snippet.prefix.first().unwrap().clone(),
23058                            kind: Some(CompletionItemKind::SNIPPET),
23059                            label_details: snippet.description.as_ref().map(|description| {
23060                                lsp::CompletionItemLabelDetails {
23061                                    detail: Some(description.clone()),
23062                                    description: None,
23063                                }
23064                            }),
23065                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23066                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23067                                lsp::InsertReplaceEdit {
23068                                    new_text: snippet.body.clone(),
23069                                    insert: lsp_range,
23070                                    replace: lsp_range,
23071                                },
23072                            )),
23073                            filter_text: Some(snippet.body.clone()),
23074                            sort_text: Some(char::MAX.to_string()),
23075                            ..lsp::CompletionItem::default()
23076                        }),
23077                        lsp_defaults: None,
23078                    },
23079                    label: CodeLabel {
23080                        text: matching_prefix.clone(),
23081                        runs: Vec::new(),
23082                        filter_range: 0..matching_prefix.len(),
23083                    },
23084                    icon_path: None,
23085                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23086                        single_line: snippet.name.clone().into(),
23087                        plain_text: snippet
23088                            .description
23089                            .clone()
23090                            .map(|description| description.into()),
23091                    }),
23092                    insert_text_mode: None,
23093                    confirm: None,
23094                })
23095            }))
23096        }
23097
23098        Ok(CompletionResponse {
23099            completions,
23100            display_options: CompletionDisplayOptions::default(),
23101            is_incomplete,
23102        })
23103    })
23104}
23105
23106impl CompletionProvider for Entity<Project> {
23107    fn completions(
23108        &self,
23109        _excerpt_id: ExcerptId,
23110        buffer: &Entity<Buffer>,
23111        buffer_position: text::Anchor,
23112        options: CompletionContext,
23113        _window: &mut Window,
23114        cx: &mut Context<Editor>,
23115    ) -> Task<Result<Vec<CompletionResponse>>> {
23116        self.update(cx, |project, cx| {
23117            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23118            let project_completions = project.completions(buffer, buffer_position, options, cx);
23119            cx.background_spawn(async move {
23120                let mut responses = project_completions.await?;
23121                let snippets = snippets.await?;
23122                if !snippets.completions.is_empty() {
23123                    responses.push(snippets);
23124                }
23125                Ok(responses)
23126            })
23127        })
23128    }
23129
23130    fn resolve_completions(
23131        &self,
23132        buffer: Entity<Buffer>,
23133        completion_indices: Vec<usize>,
23134        completions: Rc<RefCell<Box<[Completion]>>>,
23135        cx: &mut Context<Editor>,
23136    ) -> Task<Result<bool>> {
23137        self.update(cx, |project, cx| {
23138            project.lsp_store().update(cx, |lsp_store, cx| {
23139                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23140            })
23141        })
23142    }
23143
23144    fn apply_additional_edits_for_completion(
23145        &self,
23146        buffer: Entity<Buffer>,
23147        completions: Rc<RefCell<Box<[Completion]>>>,
23148        completion_index: usize,
23149        push_to_history: bool,
23150        cx: &mut Context<Editor>,
23151    ) -> Task<Result<Option<language::Transaction>>> {
23152        self.update(cx, |project, cx| {
23153            project.lsp_store().update(cx, |lsp_store, cx| {
23154                lsp_store.apply_additional_edits_for_completion(
23155                    buffer,
23156                    completions,
23157                    completion_index,
23158                    push_to_history,
23159                    cx,
23160                )
23161            })
23162        })
23163    }
23164
23165    fn is_completion_trigger(
23166        &self,
23167        buffer: &Entity<Buffer>,
23168        position: language::Anchor,
23169        text: &str,
23170        trigger_in_words: bool,
23171        menu_is_open: bool,
23172        cx: &mut Context<Editor>,
23173    ) -> bool {
23174        let mut chars = text.chars();
23175        let char = if let Some(char) = chars.next() {
23176            char
23177        } else {
23178            return false;
23179        };
23180        if chars.next().is_some() {
23181            return false;
23182        }
23183
23184        let buffer = buffer.read(cx);
23185        let snapshot = buffer.snapshot();
23186        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23187            return false;
23188        }
23189        let classifier = snapshot
23190            .char_classifier_at(position)
23191            .scope_context(Some(CharScopeContext::Completion));
23192        if trigger_in_words && classifier.is_word(char) {
23193            return true;
23194        }
23195
23196        buffer.completion_triggers().contains(text)
23197    }
23198}
23199
23200impl SemanticsProvider for Entity<Project> {
23201    fn hover(
23202        &self,
23203        buffer: &Entity<Buffer>,
23204        position: text::Anchor,
23205        cx: &mut App,
23206    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23207        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23208    }
23209
23210    fn document_highlights(
23211        &self,
23212        buffer: &Entity<Buffer>,
23213        position: text::Anchor,
23214        cx: &mut App,
23215    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23216        Some(self.update(cx, |project, cx| {
23217            project.document_highlights(buffer, position, cx)
23218        }))
23219    }
23220
23221    fn definitions(
23222        &self,
23223        buffer: &Entity<Buffer>,
23224        position: text::Anchor,
23225        kind: GotoDefinitionKind,
23226        cx: &mut App,
23227    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23228        Some(self.update(cx, |project, cx| match kind {
23229            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23230            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23231            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23232            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23233        }))
23234    }
23235
23236    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23237        self.update(cx, |project, cx| {
23238            if project
23239                .active_debug_session(cx)
23240                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23241            {
23242                return true;
23243            }
23244
23245            buffer.update(cx, |buffer, cx| {
23246                project.any_language_server_supports_inlay_hints(buffer, cx)
23247            })
23248        })
23249    }
23250
23251    fn inline_values(
23252        &self,
23253        buffer_handle: Entity<Buffer>,
23254        range: Range<text::Anchor>,
23255        cx: &mut App,
23256    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23257        self.update(cx, |project, cx| {
23258            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23259
23260            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23261        })
23262    }
23263
23264    fn inlay_hints(
23265        &self,
23266        buffer_handle: Entity<Buffer>,
23267        range: Range<text::Anchor>,
23268        cx: &mut App,
23269    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23270        Some(self.update(cx, |project, cx| {
23271            project.inlay_hints(buffer_handle, range, cx)
23272        }))
23273    }
23274
23275    fn resolve_inlay_hint(
23276        &self,
23277        hint: InlayHint,
23278        buffer_handle: Entity<Buffer>,
23279        server_id: LanguageServerId,
23280        cx: &mut App,
23281    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23282        Some(self.update(cx, |project, cx| {
23283            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23284        }))
23285    }
23286
23287    fn range_for_rename(
23288        &self,
23289        buffer: &Entity<Buffer>,
23290        position: text::Anchor,
23291        cx: &mut App,
23292    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23293        Some(self.update(cx, |project, cx| {
23294            let buffer = buffer.clone();
23295            let task = project.prepare_rename(buffer.clone(), position, cx);
23296            cx.spawn(async move |_, cx| {
23297                Ok(match task.await? {
23298                    PrepareRenameResponse::Success(range) => Some(range),
23299                    PrepareRenameResponse::InvalidPosition => None,
23300                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23301                        // Fallback on using TreeSitter info to determine identifier range
23302                        buffer.read_with(cx, |buffer, _| {
23303                            let snapshot = buffer.snapshot();
23304                            let (range, kind) = snapshot.surrounding_word(position, None);
23305                            if kind != Some(CharKind::Word) {
23306                                return None;
23307                            }
23308                            Some(
23309                                snapshot.anchor_before(range.start)
23310                                    ..snapshot.anchor_after(range.end),
23311                            )
23312                        })?
23313                    }
23314                })
23315            })
23316        }))
23317    }
23318
23319    fn perform_rename(
23320        &self,
23321        buffer: &Entity<Buffer>,
23322        position: text::Anchor,
23323        new_name: String,
23324        cx: &mut App,
23325    ) -> Option<Task<Result<ProjectTransaction>>> {
23326        Some(self.update(cx, |project, cx| {
23327            project.perform_rename(buffer.clone(), position, new_name, cx)
23328        }))
23329    }
23330}
23331
23332fn inlay_hint_settings(
23333    location: Anchor,
23334    snapshot: &MultiBufferSnapshot,
23335    cx: &mut Context<Editor>,
23336) -> InlayHintSettings {
23337    let file = snapshot.file_at(location);
23338    let language = snapshot.language_at(location).map(|l| l.name());
23339    language_settings(language, file, cx).inlay_hints
23340}
23341
23342fn consume_contiguous_rows(
23343    contiguous_row_selections: &mut Vec<Selection<Point>>,
23344    selection: &Selection<Point>,
23345    display_map: &DisplaySnapshot,
23346    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23347) -> (MultiBufferRow, MultiBufferRow) {
23348    contiguous_row_selections.push(selection.clone());
23349    let start_row = starting_row(selection, display_map);
23350    let mut end_row = ending_row(selection, display_map);
23351
23352    while let Some(next_selection) = selections.peek() {
23353        if next_selection.start.row <= end_row.0 {
23354            end_row = ending_row(next_selection, display_map);
23355            contiguous_row_selections.push(selections.next().unwrap().clone());
23356        } else {
23357            break;
23358        }
23359    }
23360    (start_row, end_row)
23361}
23362
23363fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23364    if selection.start.column > 0 {
23365        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23366    } else {
23367        MultiBufferRow(selection.start.row)
23368    }
23369}
23370
23371fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23372    if next_selection.end.column > 0 || next_selection.is_empty() {
23373        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23374    } else {
23375        MultiBufferRow(next_selection.end.row)
23376    }
23377}
23378
23379impl EditorSnapshot {
23380    pub fn remote_selections_in_range<'a>(
23381        &'a self,
23382        range: &'a Range<Anchor>,
23383        collaboration_hub: &dyn CollaborationHub,
23384        cx: &'a App,
23385    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23386        let participant_names = collaboration_hub.user_names(cx);
23387        let participant_indices = collaboration_hub.user_participant_indices(cx);
23388        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23389        let collaborators_by_replica_id = collaborators_by_peer_id
23390            .values()
23391            .map(|collaborator| (collaborator.replica_id, collaborator))
23392            .collect::<HashMap<_, _>>();
23393        self.buffer_snapshot()
23394            .selections_in_range(range, false)
23395            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23396                if replica_id == AGENT_REPLICA_ID {
23397                    Some(RemoteSelection {
23398                        replica_id,
23399                        selection,
23400                        cursor_shape,
23401                        line_mode,
23402                        collaborator_id: CollaboratorId::Agent,
23403                        user_name: Some("Agent".into()),
23404                        color: cx.theme().players().agent(),
23405                    })
23406                } else {
23407                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23408                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23409                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23410                    Some(RemoteSelection {
23411                        replica_id,
23412                        selection,
23413                        cursor_shape,
23414                        line_mode,
23415                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23416                        user_name,
23417                        color: if let Some(index) = participant_index {
23418                            cx.theme().players().color_for_participant(index.0)
23419                        } else {
23420                            cx.theme().players().absent()
23421                        },
23422                    })
23423                }
23424            })
23425    }
23426
23427    pub fn hunks_for_ranges(
23428        &self,
23429        ranges: impl IntoIterator<Item = Range<Point>>,
23430    ) -> Vec<MultiBufferDiffHunk> {
23431        let mut hunks = Vec::new();
23432        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23433            HashMap::default();
23434        for query_range in ranges {
23435            let query_rows =
23436                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23437            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23438                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23439            ) {
23440                // Include deleted hunks that are adjacent to the query range, because
23441                // otherwise they would be missed.
23442                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23443                if hunk.status().is_deleted() {
23444                    intersects_range |= hunk.row_range.start == query_rows.end;
23445                    intersects_range |= hunk.row_range.end == query_rows.start;
23446                }
23447                if intersects_range {
23448                    if !processed_buffer_rows
23449                        .entry(hunk.buffer_id)
23450                        .or_default()
23451                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23452                    {
23453                        continue;
23454                    }
23455                    hunks.push(hunk);
23456                }
23457            }
23458        }
23459
23460        hunks
23461    }
23462
23463    fn display_diff_hunks_for_rows<'a>(
23464        &'a self,
23465        display_rows: Range<DisplayRow>,
23466        folded_buffers: &'a HashSet<BufferId>,
23467    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23468        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23469        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23470
23471        self.buffer_snapshot()
23472            .diff_hunks_in_range(buffer_start..buffer_end)
23473            .filter_map(|hunk| {
23474                if folded_buffers.contains(&hunk.buffer_id) {
23475                    return None;
23476                }
23477
23478                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23479                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23480
23481                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23482                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23483
23484                let display_hunk = if hunk_display_start.column() != 0 {
23485                    DisplayDiffHunk::Folded {
23486                        display_row: hunk_display_start.row(),
23487                    }
23488                } else {
23489                    let mut end_row = hunk_display_end.row();
23490                    if hunk_display_end.column() > 0 {
23491                        end_row.0 += 1;
23492                    }
23493                    let is_created_file = hunk.is_created_file();
23494                    DisplayDiffHunk::Unfolded {
23495                        status: hunk.status(),
23496                        diff_base_byte_range: hunk.diff_base_byte_range,
23497                        display_row_range: hunk_display_start.row()..end_row,
23498                        multi_buffer_range: Anchor::range_in_buffer(
23499                            hunk.excerpt_id,
23500                            hunk.buffer_id,
23501                            hunk.buffer_range,
23502                        ),
23503                        is_created_file,
23504                    }
23505                };
23506
23507                Some(display_hunk)
23508            })
23509    }
23510
23511    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23512        self.display_snapshot
23513            .buffer_snapshot()
23514            .language_at(position)
23515    }
23516
23517    pub fn is_focused(&self) -> bool {
23518        self.is_focused
23519    }
23520
23521    pub fn placeholder_text(&self) -> Option<String> {
23522        self.placeholder_display_snapshot
23523            .as_ref()
23524            .map(|display_map| display_map.text())
23525    }
23526
23527    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23528        self.scroll_anchor.scroll_position(&self.display_snapshot)
23529    }
23530
23531    fn gutter_dimensions(
23532        &self,
23533        font_id: FontId,
23534        font_size: Pixels,
23535        max_line_number_width: Pixels,
23536        cx: &App,
23537    ) -> Option<GutterDimensions> {
23538        if !self.show_gutter {
23539            return None;
23540        }
23541
23542        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23543        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23544
23545        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23546            matches!(
23547                ProjectSettings::get_global(cx).git.git_gutter,
23548                GitGutterSetting::TrackedFiles
23549            )
23550        });
23551        let gutter_settings = EditorSettings::get_global(cx).gutter;
23552        let show_line_numbers = self
23553            .show_line_numbers
23554            .unwrap_or(gutter_settings.line_numbers);
23555        let line_gutter_width = if show_line_numbers {
23556            // Avoid flicker-like gutter resizes when the line number gains another digit by
23557            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23558            let min_width_for_number_on_gutter =
23559                ch_advance * gutter_settings.min_line_number_digits as f32;
23560            max_line_number_width.max(min_width_for_number_on_gutter)
23561        } else {
23562            0.0.into()
23563        };
23564
23565        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23566        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23567
23568        let git_blame_entries_width =
23569            self.git_blame_gutter_max_author_length
23570                .map(|max_author_length| {
23571                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23572                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23573
23574                    /// The number of characters to dedicate to gaps and margins.
23575                    const SPACING_WIDTH: usize = 4;
23576
23577                    let max_char_count = max_author_length.min(renderer.max_author_length())
23578                        + ::git::SHORT_SHA_LENGTH
23579                        + MAX_RELATIVE_TIMESTAMP.len()
23580                        + SPACING_WIDTH;
23581
23582                    ch_advance * max_char_count
23583                });
23584
23585        let is_singleton = self.buffer_snapshot().is_singleton();
23586
23587        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23588        left_padding += if !is_singleton {
23589            ch_width * 4.0
23590        } else if show_runnables || show_breakpoints {
23591            ch_width * 3.0
23592        } else if show_git_gutter && show_line_numbers {
23593            ch_width * 2.0
23594        } else if show_git_gutter || show_line_numbers {
23595            ch_width
23596        } else {
23597            px(0.)
23598        };
23599
23600        let shows_folds = is_singleton && gutter_settings.folds;
23601
23602        let right_padding = if shows_folds && show_line_numbers {
23603            ch_width * 4.0
23604        } else if shows_folds || (!is_singleton && show_line_numbers) {
23605            ch_width * 3.0
23606        } else if show_line_numbers {
23607            ch_width
23608        } else {
23609            px(0.)
23610        };
23611
23612        Some(GutterDimensions {
23613            left_padding,
23614            right_padding,
23615            width: line_gutter_width + left_padding + right_padding,
23616            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23617            git_blame_entries_width,
23618        })
23619    }
23620
23621    pub fn render_crease_toggle(
23622        &self,
23623        buffer_row: MultiBufferRow,
23624        row_contains_cursor: bool,
23625        editor: Entity<Editor>,
23626        window: &mut Window,
23627        cx: &mut App,
23628    ) -> Option<AnyElement> {
23629        let folded = self.is_line_folded(buffer_row);
23630        let mut is_foldable = false;
23631
23632        if let Some(crease) = self
23633            .crease_snapshot
23634            .query_row(buffer_row, self.buffer_snapshot())
23635        {
23636            is_foldable = true;
23637            match crease {
23638                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23639                    if let Some(render_toggle) = render_toggle {
23640                        let toggle_callback =
23641                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23642                                if folded {
23643                                    editor.update(cx, |editor, cx| {
23644                                        editor.fold_at(buffer_row, window, cx)
23645                                    });
23646                                } else {
23647                                    editor.update(cx, |editor, cx| {
23648                                        editor.unfold_at(buffer_row, window, cx)
23649                                    });
23650                                }
23651                            });
23652                        return Some((render_toggle)(
23653                            buffer_row,
23654                            folded,
23655                            toggle_callback,
23656                            window,
23657                            cx,
23658                        ));
23659                    }
23660                }
23661            }
23662        }
23663
23664        is_foldable |= self.starts_indent(buffer_row);
23665
23666        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23667            Some(
23668                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23669                    .toggle_state(folded)
23670                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23671                        if folded {
23672                            this.unfold_at(buffer_row, window, cx);
23673                        } else {
23674                            this.fold_at(buffer_row, window, cx);
23675                        }
23676                    }))
23677                    .into_any_element(),
23678            )
23679        } else {
23680            None
23681        }
23682    }
23683
23684    pub fn render_crease_trailer(
23685        &self,
23686        buffer_row: MultiBufferRow,
23687        window: &mut Window,
23688        cx: &mut App,
23689    ) -> Option<AnyElement> {
23690        let folded = self.is_line_folded(buffer_row);
23691        if let Crease::Inline { render_trailer, .. } = self
23692            .crease_snapshot
23693            .query_row(buffer_row, self.buffer_snapshot())?
23694        {
23695            let render_trailer = render_trailer.as_ref()?;
23696            Some(render_trailer(buffer_row, folded, window, cx))
23697        } else {
23698            None
23699        }
23700    }
23701}
23702
23703impl Deref for EditorSnapshot {
23704    type Target = DisplaySnapshot;
23705
23706    fn deref(&self) -> &Self::Target {
23707        &self.display_snapshot
23708    }
23709}
23710
23711#[derive(Clone, Debug, PartialEq, Eq)]
23712pub enum EditorEvent {
23713    InputIgnored {
23714        text: Arc<str>,
23715    },
23716    InputHandled {
23717        utf16_range_to_replace: Option<Range<isize>>,
23718        text: Arc<str>,
23719    },
23720    ExcerptsAdded {
23721        buffer: Entity<Buffer>,
23722        predecessor: ExcerptId,
23723        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23724    },
23725    ExcerptsRemoved {
23726        ids: Vec<ExcerptId>,
23727        removed_buffer_ids: Vec<BufferId>,
23728    },
23729    BufferFoldToggled {
23730        ids: Vec<ExcerptId>,
23731        folded: bool,
23732    },
23733    ExcerptsEdited {
23734        ids: Vec<ExcerptId>,
23735    },
23736    ExcerptsExpanded {
23737        ids: Vec<ExcerptId>,
23738    },
23739    BufferEdited,
23740    Edited {
23741        transaction_id: clock::Lamport,
23742    },
23743    Reparsed(BufferId),
23744    Focused,
23745    FocusedIn,
23746    Blurred,
23747    DirtyChanged,
23748    Saved,
23749    TitleChanged,
23750    SelectionsChanged {
23751        local: bool,
23752    },
23753    ScrollPositionChanged {
23754        local: bool,
23755        autoscroll: bool,
23756    },
23757    TransactionUndone {
23758        transaction_id: clock::Lamport,
23759    },
23760    TransactionBegun {
23761        transaction_id: clock::Lamport,
23762    },
23763    CursorShapeChanged,
23764    BreadcrumbsChanged,
23765    PushedToNavHistory {
23766        anchor: Anchor,
23767        is_deactivate: bool,
23768    },
23769}
23770
23771impl EventEmitter<EditorEvent> for Editor {}
23772
23773impl Focusable for Editor {
23774    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23775        self.focus_handle.clone()
23776    }
23777}
23778
23779impl Render for Editor {
23780    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23781        let settings = ThemeSettings::get_global(cx);
23782
23783        let mut text_style = match self.mode {
23784            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23785                color: cx.theme().colors().editor_foreground,
23786                font_family: settings.ui_font.family.clone(),
23787                font_features: settings.ui_font.features.clone(),
23788                font_fallbacks: settings.ui_font.fallbacks.clone(),
23789                font_size: rems(0.875).into(),
23790                font_weight: settings.ui_font.weight,
23791                line_height: relative(settings.buffer_line_height.value()),
23792                ..Default::default()
23793            },
23794            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23795                color: cx.theme().colors().editor_foreground,
23796                font_family: settings.buffer_font.family.clone(),
23797                font_features: settings.buffer_font.features.clone(),
23798                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23799                font_size: settings.buffer_font_size(cx).into(),
23800                font_weight: settings.buffer_font.weight,
23801                line_height: relative(settings.buffer_line_height.value()),
23802                ..Default::default()
23803            },
23804        };
23805        if let Some(text_style_refinement) = &self.text_style_refinement {
23806            text_style.refine(text_style_refinement)
23807        }
23808
23809        let background = match self.mode {
23810            EditorMode::SingleLine => cx.theme().system().transparent,
23811            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23812            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23813            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23814        };
23815
23816        EditorElement::new(
23817            &cx.entity(),
23818            EditorStyle {
23819                background,
23820                border: cx.theme().colors().border,
23821                local_player: cx.theme().players().local(),
23822                text: text_style,
23823                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23824                syntax: cx.theme().syntax().clone(),
23825                status: cx.theme().status().clone(),
23826                inlay_hints_style: make_inlay_hints_style(cx),
23827                edit_prediction_styles: make_suggestion_styles(cx),
23828                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23829                show_underlines: self.diagnostics_enabled(),
23830            },
23831        )
23832    }
23833}
23834
23835impl EntityInputHandler for Editor {
23836    fn text_for_range(
23837        &mut self,
23838        range_utf16: Range<usize>,
23839        adjusted_range: &mut Option<Range<usize>>,
23840        _: &mut Window,
23841        cx: &mut Context<Self>,
23842    ) -> Option<String> {
23843        let snapshot = self.buffer.read(cx).read(cx);
23844        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23845        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23846        if (start.0..end.0) != range_utf16 {
23847            adjusted_range.replace(start.0..end.0);
23848        }
23849        Some(snapshot.text_for_range(start..end).collect())
23850    }
23851
23852    fn selected_text_range(
23853        &mut self,
23854        ignore_disabled_input: bool,
23855        _: &mut Window,
23856        cx: &mut Context<Self>,
23857    ) -> Option<UTF16Selection> {
23858        // Prevent the IME menu from appearing when holding down an alphabetic key
23859        // while input is disabled.
23860        if !ignore_disabled_input && !self.input_enabled {
23861            return None;
23862        }
23863
23864        let selection = self.selections.newest::<OffsetUtf16>(cx);
23865        let range = selection.range();
23866
23867        Some(UTF16Selection {
23868            range: range.start.0..range.end.0,
23869            reversed: selection.reversed,
23870        })
23871    }
23872
23873    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23874        let snapshot = self.buffer.read(cx).read(cx);
23875        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23876        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23877    }
23878
23879    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23880        self.clear_highlights::<InputComposition>(cx);
23881        self.ime_transaction.take();
23882    }
23883
23884    fn replace_text_in_range(
23885        &mut self,
23886        range_utf16: Option<Range<usize>>,
23887        text: &str,
23888        window: &mut Window,
23889        cx: &mut Context<Self>,
23890    ) {
23891        if !self.input_enabled {
23892            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23893            return;
23894        }
23895
23896        self.transact(window, cx, |this, window, cx| {
23897            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23898                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23899                Some(this.selection_replacement_ranges(range_utf16, cx))
23900            } else {
23901                this.marked_text_ranges(cx)
23902            };
23903
23904            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23905                let newest_selection_id = this.selections.newest_anchor().id;
23906                this.selections
23907                    .all::<OffsetUtf16>(cx)
23908                    .iter()
23909                    .zip(ranges_to_replace.iter())
23910                    .find_map(|(selection, range)| {
23911                        if selection.id == newest_selection_id {
23912                            Some(
23913                                (range.start.0 as isize - selection.head().0 as isize)
23914                                    ..(range.end.0 as isize - selection.head().0 as isize),
23915                            )
23916                        } else {
23917                            None
23918                        }
23919                    })
23920            });
23921
23922            cx.emit(EditorEvent::InputHandled {
23923                utf16_range_to_replace: range_to_replace,
23924                text: text.into(),
23925            });
23926
23927            if let Some(new_selected_ranges) = new_selected_ranges {
23928                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23929                    selections.select_ranges(new_selected_ranges)
23930                });
23931                this.backspace(&Default::default(), window, cx);
23932            }
23933
23934            this.handle_input(text, window, cx);
23935        });
23936
23937        if let Some(transaction) = self.ime_transaction {
23938            self.buffer.update(cx, |buffer, cx| {
23939                buffer.group_until_transaction(transaction, cx);
23940            });
23941        }
23942
23943        self.unmark_text(window, cx);
23944    }
23945
23946    fn replace_and_mark_text_in_range(
23947        &mut self,
23948        range_utf16: Option<Range<usize>>,
23949        text: &str,
23950        new_selected_range_utf16: Option<Range<usize>>,
23951        window: &mut Window,
23952        cx: &mut Context<Self>,
23953    ) {
23954        if !self.input_enabled {
23955            return;
23956        }
23957
23958        let transaction = self.transact(window, cx, |this, window, cx| {
23959            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23960                let snapshot = this.buffer.read(cx).read(cx);
23961                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23962                    for marked_range in &mut marked_ranges {
23963                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23964                        marked_range.start.0 += relative_range_utf16.start;
23965                        marked_range.start =
23966                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23967                        marked_range.end =
23968                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23969                    }
23970                }
23971                Some(marked_ranges)
23972            } else if let Some(range_utf16) = range_utf16 {
23973                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23974                Some(this.selection_replacement_ranges(range_utf16, cx))
23975            } else {
23976                None
23977            };
23978
23979            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23980                let newest_selection_id = this.selections.newest_anchor().id;
23981                this.selections
23982                    .all::<OffsetUtf16>(cx)
23983                    .iter()
23984                    .zip(ranges_to_replace.iter())
23985                    .find_map(|(selection, range)| {
23986                        if selection.id == newest_selection_id {
23987                            Some(
23988                                (range.start.0 as isize - selection.head().0 as isize)
23989                                    ..(range.end.0 as isize - selection.head().0 as isize),
23990                            )
23991                        } else {
23992                            None
23993                        }
23994                    })
23995            });
23996
23997            cx.emit(EditorEvent::InputHandled {
23998                utf16_range_to_replace: range_to_replace,
23999                text: text.into(),
24000            });
24001
24002            if let Some(ranges) = ranges_to_replace {
24003                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24004                    s.select_ranges(ranges)
24005                });
24006            }
24007
24008            let marked_ranges = {
24009                let snapshot = this.buffer.read(cx).read(cx);
24010                this.selections
24011                    .disjoint_anchors_arc()
24012                    .iter()
24013                    .map(|selection| {
24014                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24015                    })
24016                    .collect::<Vec<_>>()
24017            };
24018
24019            if text.is_empty() {
24020                this.unmark_text(window, cx);
24021            } else {
24022                this.highlight_text::<InputComposition>(
24023                    marked_ranges.clone(),
24024                    HighlightStyle {
24025                        underline: Some(UnderlineStyle {
24026                            thickness: px(1.),
24027                            color: None,
24028                            wavy: false,
24029                        }),
24030                        ..Default::default()
24031                    },
24032                    cx,
24033                );
24034            }
24035
24036            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24037            let use_autoclose = this.use_autoclose;
24038            let use_auto_surround = this.use_auto_surround;
24039            this.set_use_autoclose(false);
24040            this.set_use_auto_surround(false);
24041            this.handle_input(text, window, cx);
24042            this.set_use_autoclose(use_autoclose);
24043            this.set_use_auto_surround(use_auto_surround);
24044
24045            if let Some(new_selected_range) = new_selected_range_utf16 {
24046                let snapshot = this.buffer.read(cx).read(cx);
24047                let new_selected_ranges = marked_ranges
24048                    .into_iter()
24049                    .map(|marked_range| {
24050                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24051                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24052                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24053                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24054                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24055                    })
24056                    .collect::<Vec<_>>();
24057
24058                drop(snapshot);
24059                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24060                    selections.select_ranges(new_selected_ranges)
24061                });
24062            }
24063        });
24064
24065        self.ime_transaction = self.ime_transaction.or(transaction);
24066        if let Some(transaction) = self.ime_transaction {
24067            self.buffer.update(cx, |buffer, cx| {
24068                buffer.group_until_transaction(transaction, cx);
24069            });
24070        }
24071
24072        if self.text_highlights::<InputComposition>(cx).is_none() {
24073            self.ime_transaction.take();
24074        }
24075    }
24076
24077    fn bounds_for_range(
24078        &mut self,
24079        range_utf16: Range<usize>,
24080        element_bounds: gpui::Bounds<Pixels>,
24081        window: &mut Window,
24082        cx: &mut Context<Self>,
24083    ) -> Option<gpui::Bounds<Pixels>> {
24084        let text_layout_details = self.text_layout_details(window);
24085        let CharacterDimensions {
24086            em_width,
24087            em_advance,
24088            line_height,
24089        } = self.character_dimensions(window);
24090
24091        let snapshot = self.snapshot(window, cx);
24092        let scroll_position = snapshot.scroll_position();
24093        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24094
24095        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24096        let x = Pixels::from(
24097            ScrollOffset::from(
24098                snapshot.x_for_display_point(start, &text_layout_details)
24099                    + self.gutter_dimensions.full_width(),
24100            ) - scroll_left,
24101        );
24102        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24103
24104        Some(Bounds {
24105            origin: element_bounds.origin + point(x, y),
24106            size: size(em_width, line_height),
24107        })
24108    }
24109
24110    fn character_index_for_point(
24111        &mut self,
24112        point: gpui::Point<Pixels>,
24113        _window: &mut Window,
24114        _cx: &mut Context<Self>,
24115    ) -> Option<usize> {
24116        let position_map = self.last_position_map.as_ref()?;
24117        if !position_map.text_hitbox.contains(&point) {
24118            return None;
24119        }
24120        let display_point = position_map.point_for_position(point).previous_valid;
24121        let anchor = position_map
24122            .snapshot
24123            .display_point_to_anchor(display_point, Bias::Left);
24124        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24125        Some(utf16_offset.0)
24126    }
24127}
24128
24129trait SelectionExt {
24130    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24131    fn spanned_rows(
24132        &self,
24133        include_end_if_at_line_start: bool,
24134        map: &DisplaySnapshot,
24135    ) -> Range<MultiBufferRow>;
24136}
24137
24138impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24139    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24140        let start = self
24141            .start
24142            .to_point(map.buffer_snapshot())
24143            .to_display_point(map);
24144        let end = self
24145            .end
24146            .to_point(map.buffer_snapshot())
24147            .to_display_point(map);
24148        if self.reversed {
24149            end..start
24150        } else {
24151            start..end
24152        }
24153    }
24154
24155    fn spanned_rows(
24156        &self,
24157        include_end_if_at_line_start: bool,
24158        map: &DisplaySnapshot,
24159    ) -> Range<MultiBufferRow> {
24160        let start = self.start.to_point(map.buffer_snapshot());
24161        let mut end = self.end.to_point(map.buffer_snapshot());
24162        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24163            end.row -= 1;
24164        }
24165
24166        let buffer_start = map.prev_line_boundary(start).0;
24167        let buffer_end = map.next_line_boundary(end).0;
24168        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24169    }
24170}
24171
24172impl<T: InvalidationRegion> InvalidationStack<T> {
24173    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24174    where
24175        S: Clone + ToOffset,
24176    {
24177        while let Some(region) = self.last() {
24178            let all_selections_inside_invalidation_ranges =
24179                if selections.len() == region.ranges().len() {
24180                    selections
24181                        .iter()
24182                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24183                        .all(|(selection, invalidation_range)| {
24184                            let head = selection.head().to_offset(buffer);
24185                            invalidation_range.start <= head && invalidation_range.end >= head
24186                        })
24187                } else {
24188                    false
24189                };
24190
24191            if all_selections_inside_invalidation_ranges {
24192                break;
24193            } else {
24194                self.pop();
24195            }
24196        }
24197    }
24198}
24199
24200impl<T> Default for InvalidationStack<T> {
24201    fn default() -> Self {
24202        Self(Default::default())
24203    }
24204}
24205
24206impl<T> Deref for InvalidationStack<T> {
24207    type Target = Vec<T>;
24208
24209    fn deref(&self) -> &Self::Target {
24210        &self.0
24211    }
24212}
24213
24214impl<T> DerefMut for InvalidationStack<T> {
24215    fn deref_mut(&mut self) -> &mut Self::Target {
24216        &mut self.0
24217    }
24218}
24219
24220impl InvalidationRegion for SnippetState {
24221    fn ranges(&self) -> &[Range<Anchor>] {
24222        &self.ranges[self.active_index]
24223    }
24224}
24225
24226fn edit_prediction_edit_text(
24227    current_snapshot: &BufferSnapshot,
24228    edits: &[(Range<Anchor>, String)],
24229    edit_preview: &EditPreview,
24230    include_deletions: bool,
24231    cx: &App,
24232) -> HighlightedText {
24233    let edits = edits
24234        .iter()
24235        .map(|(anchor, text)| {
24236            (
24237                anchor.start.text_anchor..anchor.end.text_anchor,
24238                text.clone(),
24239            )
24240        })
24241        .collect::<Vec<_>>();
24242
24243    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24244}
24245
24246fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24247    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24248    // Just show the raw edit text with basic styling
24249    let mut text = String::new();
24250    let mut highlights = Vec::new();
24251
24252    let insertion_highlight_style = HighlightStyle {
24253        color: Some(cx.theme().colors().text),
24254        ..Default::default()
24255    };
24256
24257    for (_, edit_text) in edits {
24258        let start_offset = text.len();
24259        text.push_str(edit_text);
24260        let end_offset = text.len();
24261
24262        if start_offset < end_offset {
24263            highlights.push((start_offset..end_offset, insertion_highlight_style));
24264        }
24265    }
24266
24267    HighlightedText {
24268        text: text.into(),
24269        highlights,
24270    }
24271}
24272
24273pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24274    match severity {
24275        lsp::DiagnosticSeverity::ERROR => colors.error,
24276        lsp::DiagnosticSeverity::WARNING => colors.warning,
24277        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24278        lsp::DiagnosticSeverity::HINT => colors.info,
24279        _ => colors.ignored,
24280    }
24281}
24282
24283pub fn styled_runs_for_code_label<'a>(
24284    label: &'a CodeLabel,
24285    syntax_theme: &'a theme::SyntaxTheme,
24286) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24287    let fade_out = HighlightStyle {
24288        fade_out: Some(0.35),
24289        ..Default::default()
24290    };
24291
24292    let mut prev_end = label.filter_range.end;
24293    label
24294        .runs
24295        .iter()
24296        .enumerate()
24297        .flat_map(move |(ix, (range, highlight_id))| {
24298            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24299                style
24300            } else {
24301                return Default::default();
24302            };
24303            let muted_style = style.highlight(fade_out);
24304
24305            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24306            if range.start >= label.filter_range.end {
24307                if range.start > prev_end {
24308                    runs.push((prev_end..range.start, fade_out));
24309                }
24310                runs.push((range.clone(), muted_style));
24311            } else if range.end <= label.filter_range.end {
24312                runs.push((range.clone(), style));
24313            } else {
24314                runs.push((range.start..label.filter_range.end, style));
24315                runs.push((label.filter_range.end..range.end, muted_style));
24316            }
24317            prev_end = cmp::max(prev_end, range.end);
24318
24319            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24320                runs.push((prev_end..label.text.len(), fade_out));
24321            }
24322
24323            runs
24324        })
24325}
24326
24327pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24328    let mut prev_index = 0;
24329    let mut prev_codepoint: Option<char> = None;
24330    text.char_indices()
24331        .chain([(text.len(), '\0')])
24332        .filter_map(move |(index, codepoint)| {
24333            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24334            let is_boundary = index == text.len()
24335                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24336                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24337            if is_boundary {
24338                let chunk = &text[prev_index..index];
24339                prev_index = index;
24340                Some(chunk)
24341            } else {
24342                None
24343            }
24344        })
24345}
24346
24347pub trait RangeToAnchorExt: Sized {
24348    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24349
24350    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24351        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24352        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24353    }
24354}
24355
24356impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24357    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24358        let start_offset = self.start.to_offset(snapshot);
24359        let end_offset = self.end.to_offset(snapshot);
24360        if start_offset == end_offset {
24361            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24362        } else {
24363            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24364        }
24365    }
24366}
24367
24368pub trait RowExt {
24369    fn as_f64(&self) -> f64;
24370
24371    fn next_row(&self) -> Self;
24372
24373    fn previous_row(&self) -> Self;
24374
24375    fn minus(&self, other: Self) -> u32;
24376}
24377
24378impl RowExt for DisplayRow {
24379    fn as_f64(&self) -> f64 {
24380        self.0 as _
24381    }
24382
24383    fn next_row(&self) -> Self {
24384        Self(self.0 + 1)
24385    }
24386
24387    fn previous_row(&self) -> Self {
24388        Self(self.0.saturating_sub(1))
24389    }
24390
24391    fn minus(&self, other: Self) -> u32 {
24392        self.0 - other.0
24393    }
24394}
24395
24396impl RowExt for MultiBufferRow {
24397    fn as_f64(&self) -> f64 {
24398        self.0 as _
24399    }
24400
24401    fn next_row(&self) -> Self {
24402        Self(self.0 + 1)
24403    }
24404
24405    fn previous_row(&self) -> Self {
24406        Self(self.0.saturating_sub(1))
24407    }
24408
24409    fn minus(&self, other: Self) -> u32 {
24410        self.0 - other.0
24411    }
24412}
24413
24414trait RowRangeExt {
24415    type Row;
24416
24417    fn len(&self) -> usize;
24418
24419    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24420}
24421
24422impl RowRangeExt for Range<MultiBufferRow> {
24423    type Row = MultiBufferRow;
24424
24425    fn len(&self) -> usize {
24426        (self.end.0 - self.start.0) as usize
24427    }
24428
24429    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24430        (self.start.0..self.end.0).map(MultiBufferRow)
24431    }
24432}
24433
24434impl RowRangeExt for Range<DisplayRow> {
24435    type Row = DisplayRow;
24436
24437    fn len(&self) -> usize {
24438        (self.end.0 - self.start.0) as usize
24439    }
24440
24441    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24442        (self.start.0..self.end.0).map(DisplayRow)
24443    }
24444}
24445
24446/// If select range has more than one line, we
24447/// just point the cursor to range.start.
24448fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24449    if range.start.row == range.end.row {
24450        range
24451    } else {
24452        range.start..range.start
24453    }
24454}
24455pub struct KillRing(ClipboardItem);
24456impl Global for KillRing {}
24457
24458const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24459
24460enum BreakpointPromptEditAction {
24461    Log,
24462    Condition,
24463    HitCondition,
24464}
24465
24466struct BreakpointPromptEditor {
24467    pub(crate) prompt: Entity<Editor>,
24468    editor: WeakEntity<Editor>,
24469    breakpoint_anchor: Anchor,
24470    breakpoint: Breakpoint,
24471    edit_action: BreakpointPromptEditAction,
24472    block_ids: HashSet<CustomBlockId>,
24473    editor_margins: Arc<Mutex<EditorMargins>>,
24474    _subscriptions: Vec<Subscription>,
24475}
24476
24477impl BreakpointPromptEditor {
24478    const MAX_LINES: u8 = 4;
24479
24480    fn new(
24481        editor: WeakEntity<Editor>,
24482        breakpoint_anchor: Anchor,
24483        breakpoint: Breakpoint,
24484        edit_action: BreakpointPromptEditAction,
24485        window: &mut Window,
24486        cx: &mut Context<Self>,
24487    ) -> Self {
24488        let base_text = match edit_action {
24489            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24490            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24491            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24492        }
24493        .map(|msg| msg.to_string())
24494        .unwrap_or_default();
24495
24496        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24497        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24498
24499        let prompt = cx.new(|cx| {
24500            let mut prompt = Editor::new(
24501                EditorMode::AutoHeight {
24502                    min_lines: 1,
24503                    max_lines: Some(Self::MAX_LINES as usize),
24504                },
24505                buffer,
24506                None,
24507                window,
24508                cx,
24509            );
24510            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24511            prompt.set_show_cursor_when_unfocused(false, cx);
24512            prompt.set_placeholder_text(
24513                match edit_action {
24514                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24515                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24516                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24517                },
24518                window,
24519                cx,
24520            );
24521
24522            prompt
24523        });
24524
24525        Self {
24526            prompt,
24527            editor,
24528            breakpoint_anchor,
24529            breakpoint,
24530            edit_action,
24531            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24532            block_ids: Default::default(),
24533            _subscriptions: vec![],
24534        }
24535    }
24536
24537    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24538        self.block_ids.extend(block_ids)
24539    }
24540
24541    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24542        if let Some(editor) = self.editor.upgrade() {
24543            let message = self
24544                .prompt
24545                .read(cx)
24546                .buffer
24547                .read(cx)
24548                .as_singleton()
24549                .expect("A multi buffer in breakpoint prompt isn't possible")
24550                .read(cx)
24551                .as_rope()
24552                .to_string();
24553
24554            editor.update(cx, |editor, cx| {
24555                editor.edit_breakpoint_at_anchor(
24556                    self.breakpoint_anchor,
24557                    self.breakpoint.clone(),
24558                    match self.edit_action {
24559                        BreakpointPromptEditAction::Log => {
24560                            BreakpointEditAction::EditLogMessage(message.into())
24561                        }
24562                        BreakpointPromptEditAction::Condition => {
24563                            BreakpointEditAction::EditCondition(message.into())
24564                        }
24565                        BreakpointPromptEditAction::HitCondition => {
24566                            BreakpointEditAction::EditHitCondition(message.into())
24567                        }
24568                    },
24569                    cx,
24570                );
24571
24572                editor.remove_blocks(self.block_ids.clone(), None, cx);
24573                cx.focus_self(window);
24574            });
24575        }
24576    }
24577
24578    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24579        self.editor
24580            .update(cx, |editor, cx| {
24581                editor.remove_blocks(self.block_ids.clone(), None, cx);
24582                window.focus(&editor.focus_handle);
24583            })
24584            .log_err();
24585    }
24586
24587    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24588        let settings = ThemeSettings::get_global(cx);
24589        let text_style = TextStyle {
24590            color: if self.prompt.read(cx).read_only(cx) {
24591                cx.theme().colors().text_disabled
24592            } else {
24593                cx.theme().colors().text
24594            },
24595            font_family: settings.buffer_font.family.clone(),
24596            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24597            font_size: settings.buffer_font_size(cx).into(),
24598            font_weight: settings.buffer_font.weight,
24599            line_height: relative(settings.buffer_line_height.value()),
24600            ..Default::default()
24601        };
24602        EditorElement::new(
24603            &self.prompt,
24604            EditorStyle {
24605                background: cx.theme().colors().editor_background,
24606                local_player: cx.theme().players().local(),
24607                text: text_style,
24608                ..Default::default()
24609            },
24610        )
24611    }
24612}
24613
24614impl Render for BreakpointPromptEditor {
24615    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24616        let editor_margins = *self.editor_margins.lock();
24617        let gutter_dimensions = editor_margins.gutter;
24618        h_flex()
24619            .key_context("Editor")
24620            .bg(cx.theme().colors().editor_background)
24621            .border_y_1()
24622            .border_color(cx.theme().status().info_border)
24623            .size_full()
24624            .py(window.line_height() / 2.5)
24625            .on_action(cx.listener(Self::confirm))
24626            .on_action(cx.listener(Self::cancel))
24627            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24628            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24629    }
24630}
24631
24632impl Focusable for BreakpointPromptEditor {
24633    fn focus_handle(&self, cx: &App) -> FocusHandle {
24634        self.prompt.focus_handle(cx)
24635    }
24636}
24637
24638fn all_edits_insertions_or_deletions(
24639    edits: &Vec<(Range<Anchor>, String)>,
24640    snapshot: &MultiBufferSnapshot,
24641) -> bool {
24642    let mut all_insertions = true;
24643    let mut all_deletions = true;
24644
24645    for (range, new_text) in edits.iter() {
24646        let range_is_empty = range.to_offset(snapshot).is_empty();
24647        let text_is_empty = new_text.is_empty();
24648
24649        if range_is_empty != text_is_empty {
24650            if range_is_empty {
24651                all_deletions = false;
24652            } else {
24653                all_insertions = false;
24654            }
24655        } else {
24656            return false;
24657        }
24658
24659        if !all_insertions && !all_deletions {
24660            return false;
24661        }
24662    }
24663    all_insertions || all_deletions
24664}
24665
24666struct MissingEditPredictionKeybindingTooltip;
24667
24668impl Render for MissingEditPredictionKeybindingTooltip {
24669    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24670        ui::tooltip_container(cx, |container, cx| {
24671            container
24672                .flex_shrink_0()
24673                .max_w_80()
24674                .min_h(rems_from_px(124.))
24675                .justify_between()
24676                .child(
24677                    v_flex()
24678                        .flex_1()
24679                        .text_ui_sm(cx)
24680                        .child(Label::new("Conflict with Accept Keybinding"))
24681                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24682                )
24683                .child(
24684                    h_flex()
24685                        .pb_1()
24686                        .gap_1()
24687                        .items_end()
24688                        .w_full()
24689                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24690                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24691                        }))
24692                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24693                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24694                        })),
24695                )
24696        })
24697    }
24698}
24699
24700#[derive(Debug, Clone, Copy, PartialEq)]
24701pub struct LineHighlight {
24702    pub background: Background,
24703    pub border: Option<gpui::Hsla>,
24704    pub include_gutter: bool,
24705    pub type_id: Option<TypeId>,
24706}
24707
24708struct LineManipulationResult {
24709    pub new_text: String,
24710    pub line_count_before: usize,
24711    pub line_count_after: usize,
24712}
24713
24714fn render_diff_hunk_controls(
24715    row: u32,
24716    status: &DiffHunkStatus,
24717    hunk_range: Range<Anchor>,
24718    is_created_file: bool,
24719    line_height: Pixels,
24720    editor: &Entity<Editor>,
24721    _window: &mut Window,
24722    cx: &mut App,
24723) -> AnyElement {
24724    h_flex()
24725        .h(line_height)
24726        .mr_1()
24727        .gap_1()
24728        .px_0p5()
24729        .pb_1()
24730        .border_x_1()
24731        .border_b_1()
24732        .border_color(cx.theme().colors().border_variant)
24733        .rounded_b_lg()
24734        .bg(cx.theme().colors().editor_background)
24735        .gap_1()
24736        .block_mouse_except_scroll()
24737        .shadow_md()
24738        .child(if status.has_secondary_hunk() {
24739            Button::new(("stage", row as u64), "Stage")
24740                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24741                .tooltip({
24742                    let focus_handle = editor.focus_handle(cx);
24743                    move |window, cx| {
24744                        Tooltip::for_action_in(
24745                            "Stage Hunk",
24746                            &::git::ToggleStaged,
24747                            &focus_handle,
24748                            window,
24749                            cx,
24750                        )
24751                    }
24752                })
24753                .on_click({
24754                    let editor = editor.clone();
24755                    move |_event, _window, cx| {
24756                        editor.update(cx, |editor, cx| {
24757                            editor.stage_or_unstage_diff_hunks(
24758                                true,
24759                                vec![hunk_range.start..hunk_range.start],
24760                                cx,
24761                            );
24762                        });
24763                    }
24764                })
24765        } else {
24766            Button::new(("unstage", row as u64), "Unstage")
24767                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24768                .tooltip({
24769                    let focus_handle = editor.focus_handle(cx);
24770                    move |window, cx| {
24771                        Tooltip::for_action_in(
24772                            "Unstage Hunk",
24773                            &::git::ToggleStaged,
24774                            &focus_handle,
24775                            window,
24776                            cx,
24777                        )
24778                    }
24779                })
24780                .on_click({
24781                    let editor = editor.clone();
24782                    move |_event, _window, cx| {
24783                        editor.update(cx, |editor, cx| {
24784                            editor.stage_or_unstage_diff_hunks(
24785                                false,
24786                                vec![hunk_range.start..hunk_range.start],
24787                                cx,
24788                            );
24789                        });
24790                    }
24791                })
24792        })
24793        .child(
24794            Button::new(("restore", row as u64), "Restore")
24795                .tooltip({
24796                    let focus_handle = editor.focus_handle(cx);
24797                    move |window, cx| {
24798                        Tooltip::for_action_in(
24799                            "Restore Hunk",
24800                            &::git::Restore,
24801                            &focus_handle,
24802                            window,
24803                            cx,
24804                        )
24805                    }
24806                })
24807                .on_click({
24808                    let editor = editor.clone();
24809                    move |_event, window, cx| {
24810                        editor.update(cx, |editor, cx| {
24811                            let snapshot = editor.snapshot(window, cx);
24812                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24813                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24814                        });
24815                    }
24816                })
24817                .disabled(is_created_file),
24818        )
24819        .when(
24820            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24821            |el| {
24822                el.child(
24823                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24824                        .shape(IconButtonShape::Square)
24825                        .icon_size(IconSize::Small)
24826                        // .disabled(!has_multiple_hunks)
24827                        .tooltip({
24828                            let focus_handle = editor.focus_handle(cx);
24829                            move |window, cx| {
24830                                Tooltip::for_action_in(
24831                                    "Next Hunk",
24832                                    &GoToHunk,
24833                                    &focus_handle,
24834                                    window,
24835                                    cx,
24836                                )
24837                            }
24838                        })
24839                        .on_click({
24840                            let editor = editor.clone();
24841                            move |_event, window, cx| {
24842                                editor.update(cx, |editor, cx| {
24843                                    let snapshot = editor.snapshot(window, cx);
24844                                    let position =
24845                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24846                                    editor.go_to_hunk_before_or_after_position(
24847                                        &snapshot,
24848                                        position,
24849                                        Direction::Next,
24850                                        window,
24851                                        cx,
24852                                    );
24853                                    editor.expand_selected_diff_hunks(cx);
24854                                });
24855                            }
24856                        }),
24857                )
24858                .child(
24859                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24860                        .shape(IconButtonShape::Square)
24861                        .icon_size(IconSize::Small)
24862                        // .disabled(!has_multiple_hunks)
24863                        .tooltip({
24864                            let focus_handle = editor.focus_handle(cx);
24865                            move |window, cx| {
24866                                Tooltip::for_action_in(
24867                                    "Previous Hunk",
24868                                    &GoToPreviousHunk,
24869                                    &focus_handle,
24870                                    window,
24871                                    cx,
24872                                )
24873                            }
24874                        })
24875                        .on_click({
24876                            let editor = editor.clone();
24877                            move |_event, window, cx| {
24878                                editor.update(cx, |editor, cx| {
24879                                    let snapshot = editor.snapshot(window, cx);
24880                                    let point =
24881                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24882                                    editor.go_to_hunk_before_or_after_position(
24883                                        &snapshot,
24884                                        point,
24885                                        Direction::Prev,
24886                                        window,
24887                                        cx,
24888                                    );
24889                                    editor.expand_selected_diff_hunks(cx);
24890                                });
24891                            }
24892                        }),
24893                )
24894            },
24895        )
24896        .into_any_element()
24897}
24898
24899pub fn multibuffer_context_lines(cx: &App) -> u32 {
24900    EditorSettings::try_get(cx)
24901        .map(|settings| settings.excerpt_context_lines)
24902        .unwrap_or(2)
24903        .min(32)
24904}