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                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7005                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7006                    match_ranges.extend(
 7007                        regex
 7008                            .search(buffer_snapshot, Some(search_range.clone()))
 7009                            .await
 7010                            .into_iter()
 7011                            .filter_map(|match_range| {
 7012                                let match_start = buffer_snapshot
 7013                                    .anchor_after(search_range.start + match_range.start);
 7014                                let match_end = buffer_snapshot
 7015                                    .anchor_before(search_range.start + match_range.end);
 7016                                let match_anchor_range = Anchor::range_in_buffer(
 7017                                    excerpt_id,
 7018                                    buffer_snapshot.remote_id(),
 7019                                    match_start..match_end,
 7020                                );
 7021                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7022                            }),
 7023                    );
 7024                }
 7025                match_ranges
 7026            });
 7027            let match_ranges = match_task.await;
 7028            editor
 7029                .update_in(cx, |editor, _, cx| {
 7030                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7031                    if !match_ranges.is_empty() {
 7032                        editor.highlight_background::<SelectedTextHighlight>(
 7033                            &match_ranges,
 7034                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7035                            cx,
 7036                        )
 7037                    }
 7038                })
 7039                .log_err();
 7040        })
 7041    }
 7042
 7043    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7044        struct NewlineFold;
 7045        let type_id = std::any::TypeId::of::<NewlineFold>();
 7046        if !self.mode.is_single_line() {
 7047            return;
 7048        }
 7049        let snapshot = self.snapshot(window, cx);
 7050        if snapshot.buffer_snapshot().max_point().row == 0 {
 7051            return;
 7052        }
 7053        let task = cx.background_spawn(async move {
 7054            let new_newlines = snapshot
 7055                .buffer_chars_at(0)
 7056                .filter_map(|(c, i)| {
 7057                    if c == '\n' {
 7058                        Some(
 7059                            snapshot.buffer_snapshot().anchor_after(i)
 7060                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7061                        )
 7062                    } else {
 7063                        None
 7064                    }
 7065                })
 7066                .collect::<Vec<_>>();
 7067            let existing_newlines = snapshot
 7068                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7069                .filter_map(|fold| {
 7070                    if fold.placeholder.type_tag == Some(type_id) {
 7071                        Some(fold.range.start..fold.range.end)
 7072                    } else {
 7073                        None
 7074                    }
 7075                })
 7076                .collect::<Vec<_>>();
 7077
 7078            (new_newlines, existing_newlines)
 7079        });
 7080        self.folding_newlines = cx.spawn(async move |this, cx| {
 7081            let (new_newlines, existing_newlines) = task.await;
 7082            if new_newlines == existing_newlines {
 7083                return;
 7084            }
 7085            let placeholder = FoldPlaceholder {
 7086                render: Arc::new(move |_, _, cx| {
 7087                    div()
 7088                        .bg(cx.theme().status().hint_background)
 7089                        .border_b_1()
 7090                        .size_full()
 7091                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7092                        .border_color(cx.theme().status().hint)
 7093                        .child("\\n")
 7094                        .into_any()
 7095                }),
 7096                constrain_width: false,
 7097                merge_adjacent: false,
 7098                type_tag: Some(type_id),
 7099            };
 7100            let creases = new_newlines
 7101                .into_iter()
 7102                .map(|range| Crease::simple(range, placeholder.clone()))
 7103                .collect();
 7104            this.update(cx, |this, cx| {
 7105                this.display_map.update(cx, |display_map, cx| {
 7106                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7107                    display_map.fold(creases, cx);
 7108                });
 7109            })
 7110            .ok();
 7111        });
 7112    }
 7113
 7114    fn refresh_selected_text_highlights(
 7115        &mut self,
 7116        on_buffer_edit: bool,
 7117        window: &mut Window,
 7118        cx: &mut Context<Editor>,
 7119    ) {
 7120        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7121        else {
 7122            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7123            self.quick_selection_highlight_task.take();
 7124            self.debounced_selection_highlight_task.take();
 7125            return;
 7126        };
 7127        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7128        if on_buffer_edit
 7129            || self
 7130                .quick_selection_highlight_task
 7131                .as_ref()
 7132                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7133        {
 7134            let multi_buffer_visible_start = self
 7135                .scroll_manager
 7136                .anchor()
 7137                .anchor
 7138                .to_point(&multi_buffer_snapshot);
 7139            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7140                multi_buffer_visible_start
 7141                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7142                Bias::Left,
 7143            );
 7144            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7145            self.quick_selection_highlight_task = Some((
 7146                query_range.clone(),
 7147                self.update_selection_occurrence_highlights(
 7148                    query_text.clone(),
 7149                    query_range.clone(),
 7150                    multi_buffer_visible_range,
 7151                    false,
 7152                    window,
 7153                    cx,
 7154                ),
 7155            ));
 7156        }
 7157        if on_buffer_edit
 7158            || self
 7159                .debounced_selection_highlight_task
 7160                .as_ref()
 7161                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7162        {
 7163            let multi_buffer_start = multi_buffer_snapshot
 7164                .anchor_before(0)
 7165                .to_point(&multi_buffer_snapshot);
 7166            let multi_buffer_end = multi_buffer_snapshot
 7167                .anchor_after(multi_buffer_snapshot.len())
 7168                .to_point(&multi_buffer_snapshot);
 7169            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7170            self.debounced_selection_highlight_task = Some((
 7171                query_range.clone(),
 7172                self.update_selection_occurrence_highlights(
 7173                    query_text,
 7174                    query_range,
 7175                    multi_buffer_full_range,
 7176                    true,
 7177                    window,
 7178                    cx,
 7179                ),
 7180            ));
 7181        }
 7182    }
 7183
 7184    pub fn refresh_edit_prediction(
 7185        &mut self,
 7186        debounce: bool,
 7187        user_requested: bool,
 7188        window: &mut Window,
 7189        cx: &mut Context<Self>,
 7190    ) -> Option<()> {
 7191        if DisableAiSettings::get_global(cx).disable_ai {
 7192            return None;
 7193        }
 7194
 7195        let provider = self.edit_prediction_provider()?;
 7196        let cursor = self.selections.newest_anchor().head();
 7197        let (buffer, cursor_buffer_position) =
 7198            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7199
 7200        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7201            self.discard_edit_prediction(false, cx);
 7202            return None;
 7203        }
 7204
 7205        self.update_visible_edit_prediction(window, cx);
 7206
 7207        if !user_requested
 7208            && (!self.should_show_edit_predictions()
 7209                || !self.is_focused(window)
 7210                || buffer.read(cx).is_empty())
 7211        {
 7212            self.discard_edit_prediction(false, cx);
 7213            return None;
 7214        }
 7215
 7216        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7217        Some(())
 7218    }
 7219
 7220    fn show_edit_predictions_in_menu(&self) -> bool {
 7221        match self.edit_prediction_settings {
 7222            EditPredictionSettings::Disabled => false,
 7223            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7224        }
 7225    }
 7226
 7227    pub fn edit_predictions_enabled(&self) -> bool {
 7228        match self.edit_prediction_settings {
 7229            EditPredictionSettings::Disabled => false,
 7230            EditPredictionSettings::Enabled { .. } => true,
 7231        }
 7232    }
 7233
 7234    fn edit_prediction_requires_modifier(&self) -> bool {
 7235        match self.edit_prediction_settings {
 7236            EditPredictionSettings::Disabled => false,
 7237            EditPredictionSettings::Enabled {
 7238                preview_requires_modifier,
 7239                ..
 7240            } => preview_requires_modifier,
 7241        }
 7242    }
 7243
 7244    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7245        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7246            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7247            self.discard_edit_prediction(false, cx);
 7248        } else {
 7249            let selection = self.selections.newest_anchor();
 7250            let cursor = selection.head();
 7251
 7252            if let Some((buffer, cursor_buffer_position)) =
 7253                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7254            {
 7255                self.edit_prediction_settings =
 7256                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7257            }
 7258        }
 7259    }
 7260
 7261    fn edit_prediction_settings_at_position(
 7262        &self,
 7263        buffer: &Entity<Buffer>,
 7264        buffer_position: language::Anchor,
 7265        cx: &App,
 7266    ) -> EditPredictionSettings {
 7267        if !self.mode.is_full()
 7268            || !self.show_edit_predictions_override.unwrap_or(true)
 7269            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7270        {
 7271            return EditPredictionSettings::Disabled;
 7272        }
 7273
 7274        let buffer = buffer.read(cx);
 7275
 7276        let file = buffer.file();
 7277
 7278        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7279            return EditPredictionSettings::Disabled;
 7280        };
 7281
 7282        let by_provider = matches!(
 7283            self.menu_edit_predictions_policy,
 7284            MenuEditPredictionsPolicy::ByProvider
 7285        );
 7286
 7287        let show_in_menu = by_provider
 7288            && self
 7289                .edit_prediction_provider
 7290                .as_ref()
 7291                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7292
 7293        let preview_requires_modifier =
 7294            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7295
 7296        EditPredictionSettings::Enabled {
 7297            show_in_menu,
 7298            preview_requires_modifier,
 7299        }
 7300    }
 7301
 7302    fn should_show_edit_predictions(&self) -> bool {
 7303        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7304    }
 7305
 7306    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7307        matches!(
 7308            self.edit_prediction_preview,
 7309            EditPredictionPreview::Active { .. }
 7310        )
 7311    }
 7312
 7313    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7314        let cursor = self.selections.newest_anchor().head();
 7315        if let Some((buffer, cursor_position)) =
 7316            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7317        {
 7318            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7319        } else {
 7320            false
 7321        }
 7322    }
 7323
 7324    pub fn supports_minimap(&self, cx: &App) -> bool {
 7325        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7326    }
 7327
 7328    fn edit_predictions_enabled_in_buffer(
 7329        &self,
 7330        buffer: &Entity<Buffer>,
 7331        buffer_position: language::Anchor,
 7332        cx: &App,
 7333    ) -> bool {
 7334        maybe!({
 7335            if self.read_only(cx) {
 7336                return Some(false);
 7337            }
 7338            let provider = self.edit_prediction_provider()?;
 7339            if !provider.is_enabled(buffer, buffer_position, cx) {
 7340                return Some(false);
 7341            }
 7342            let buffer = buffer.read(cx);
 7343            let Some(file) = buffer.file() else {
 7344                return Some(true);
 7345            };
 7346            let settings = all_language_settings(Some(file), cx);
 7347            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7348        })
 7349        .unwrap_or(false)
 7350    }
 7351
 7352    fn cycle_edit_prediction(
 7353        &mut self,
 7354        direction: Direction,
 7355        window: &mut Window,
 7356        cx: &mut Context<Self>,
 7357    ) -> Option<()> {
 7358        let provider = self.edit_prediction_provider()?;
 7359        let cursor = self.selections.newest_anchor().head();
 7360        let (buffer, cursor_buffer_position) =
 7361            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7362        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7363            return None;
 7364        }
 7365
 7366        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7367        self.update_visible_edit_prediction(window, cx);
 7368
 7369        Some(())
 7370    }
 7371
 7372    pub fn show_edit_prediction(
 7373        &mut self,
 7374        _: &ShowEditPrediction,
 7375        window: &mut Window,
 7376        cx: &mut Context<Self>,
 7377    ) {
 7378        if !self.has_active_edit_prediction() {
 7379            self.refresh_edit_prediction(false, true, window, cx);
 7380            return;
 7381        }
 7382
 7383        self.update_visible_edit_prediction(window, cx);
 7384    }
 7385
 7386    pub fn display_cursor_names(
 7387        &mut self,
 7388        _: &DisplayCursorNames,
 7389        window: &mut Window,
 7390        cx: &mut Context<Self>,
 7391    ) {
 7392        self.show_cursor_names(window, cx);
 7393    }
 7394
 7395    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7396        self.show_cursor_names = true;
 7397        cx.notify();
 7398        cx.spawn_in(window, async move |this, cx| {
 7399            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7400            this.update(cx, |this, cx| {
 7401                this.show_cursor_names = false;
 7402                cx.notify()
 7403            })
 7404            .ok()
 7405        })
 7406        .detach();
 7407    }
 7408
 7409    pub fn next_edit_prediction(
 7410        &mut self,
 7411        _: &NextEditPrediction,
 7412        window: &mut Window,
 7413        cx: &mut Context<Self>,
 7414    ) {
 7415        if self.has_active_edit_prediction() {
 7416            self.cycle_edit_prediction(Direction::Next, window, cx);
 7417        } else {
 7418            let is_copilot_disabled = self
 7419                .refresh_edit_prediction(false, true, window, cx)
 7420                .is_none();
 7421            if is_copilot_disabled {
 7422                cx.propagate();
 7423            }
 7424        }
 7425    }
 7426
 7427    pub fn previous_edit_prediction(
 7428        &mut self,
 7429        _: &PreviousEditPrediction,
 7430        window: &mut Window,
 7431        cx: &mut Context<Self>,
 7432    ) {
 7433        if self.has_active_edit_prediction() {
 7434            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7435        } else {
 7436            let is_copilot_disabled = self
 7437                .refresh_edit_prediction(false, true, window, cx)
 7438                .is_none();
 7439            if is_copilot_disabled {
 7440                cx.propagate();
 7441            }
 7442        }
 7443    }
 7444
 7445    pub fn accept_edit_prediction(
 7446        &mut self,
 7447        _: &AcceptEditPrediction,
 7448        window: &mut Window,
 7449        cx: &mut Context<Self>,
 7450    ) {
 7451        if self.show_edit_predictions_in_menu() {
 7452            self.hide_context_menu(window, cx);
 7453        }
 7454
 7455        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7456            return;
 7457        };
 7458
 7459        match &active_edit_prediction.completion {
 7460            EditPrediction::MoveWithin { target, .. } => {
 7461                let target = *target;
 7462
 7463                if let Some(position_map) = &self.last_position_map {
 7464                    if position_map
 7465                        .visible_row_range
 7466                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7467                        || !self.edit_prediction_requires_modifier()
 7468                    {
 7469                        self.unfold_ranges(&[target..target], true, false, cx);
 7470                        // Note that this is also done in vim's handler of the Tab action.
 7471                        self.change_selections(
 7472                            SelectionEffects::scroll(Autoscroll::newest()),
 7473                            window,
 7474                            cx,
 7475                            |selections| {
 7476                                selections.select_anchor_ranges([target..target]);
 7477                            },
 7478                        );
 7479                        self.clear_row_highlights::<EditPredictionPreview>();
 7480
 7481                        self.edit_prediction_preview
 7482                            .set_previous_scroll_position(None);
 7483                    } else {
 7484                        self.edit_prediction_preview
 7485                            .set_previous_scroll_position(Some(
 7486                                position_map.snapshot.scroll_anchor,
 7487                            ));
 7488
 7489                        self.highlight_rows::<EditPredictionPreview>(
 7490                            target..target,
 7491                            cx.theme().colors().editor_highlighted_line_background,
 7492                            RowHighlightOptions {
 7493                                autoscroll: true,
 7494                                ..Default::default()
 7495                            },
 7496                            cx,
 7497                        );
 7498                        self.request_autoscroll(Autoscroll::fit(), cx);
 7499                    }
 7500                }
 7501            }
 7502            EditPrediction::MoveOutside { snapshot, target } => {
 7503                if let Some(workspace) = self.workspace() {
 7504                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7505                        .detach_and_log_err(cx);
 7506                }
 7507            }
 7508            EditPrediction::Edit { edits, .. } => {
 7509                self.report_edit_prediction_event(
 7510                    active_edit_prediction.completion_id.clone(),
 7511                    true,
 7512                    cx,
 7513                );
 7514
 7515                if let Some(provider) = self.edit_prediction_provider() {
 7516                    provider.accept(cx);
 7517                }
 7518
 7519                // Store the transaction ID and selections before applying the edit
 7520                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7521
 7522                let snapshot = self.buffer.read(cx).snapshot(cx);
 7523                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7524
 7525                self.buffer.update(cx, |buffer, cx| {
 7526                    buffer.edit(edits.iter().cloned(), None, cx)
 7527                });
 7528
 7529                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7530                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7531                });
 7532
 7533                let selections = self.selections.disjoint_anchors_arc();
 7534                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7535                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7536                    if has_new_transaction {
 7537                        self.selection_history
 7538                            .insert_transaction(transaction_id_now, selections);
 7539                    }
 7540                }
 7541
 7542                self.update_visible_edit_prediction(window, cx);
 7543                if self.active_edit_prediction.is_none() {
 7544                    self.refresh_edit_prediction(true, true, window, cx);
 7545                }
 7546
 7547                cx.notify();
 7548            }
 7549        }
 7550
 7551        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7552    }
 7553
 7554    pub fn accept_partial_edit_prediction(
 7555        &mut self,
 7556        _: &AcceptPartialEditPrediction,
 7557        window: &mut Window,
 7558        cx: &mut Context<Self>,
 7559    ) {
 7560        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7561            return;
 7562        };
 7563        if self.selections.count() != 1 {
 7564            return;
 7565        }
 7566
 7567        match &active_edit_prediction.completion {
 7568            EditPrediction::MoveWithin { target, .. } => {
 7569                let target = *target;
 7570                self.change_selections(
 7571                    SelectionEffects::scroll(Autoscroll::newest()),
 7572                    window,
 7573                    cx,
 7574                    |selections| {
 7575                        selections.select_anchor_ranges([target..target]);
 7576                    },
 7577                );
 7578            }
 7579            EditPrediction::MoveOutside { snapshot, target } => {
 7580                if let Some(workspace) = self.workspace() {
 7581                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7582                        .detach_and_log_err(cx);
 7583                }
 7584            }
 7585            EditPrediction::Edit { edits, .. } => {
 7586                self.report_edit_prediction_event(
 7587                    active_edit_prediction.completion_id.clone(),
 7588                    true,
 7589                    cx,
 7590                );
 7591
 7592                // Find an insertion that starts at the cursor position.
 7593                let snapshot = self.buffer.read(cx).snapshot(cx);
 7594                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7595                let insertion = edits.iter().find_map(|(range, text)| {
 7596                    let range = range.to_offset(&snapshot);
 7597                    if range.is_empty() && range.start == cursor_offset {
 7598                        Some(text)
 7599                    } else {
 7600                        None
 7601                    }
 7602                });
 7603
 7604                if let Some(text) = insertion {
 7605                    let mut partial_completion = text
 7606                        .chars()
 7607                        .by_ref()
 7608                        .take_while(|c| c.is_alphabetic())
 7609                        .collect::<String>();
 7610                    if partial_completion.is_empty() {
 7611                        partial_completion = text
 7612                            .chars()
 7613                            .by_ref()
 7614                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7615                            .collect::<String>();
 7616                    }
 7617
 7618                    cx.emit(EditorEvent::InputHandled {
 7619                        utf16_range_to_replace: None,
 7620                        text: partial_completion.clone().into(),
 7621                    });
 7622
 7623                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7624
 7625                    self.refresh_edit_prediction(true, true, window, cx);
 7626                    cx.notify();
 7627                } else {
 7628                    self.accept_edit_prediction(&Default::default(), window, cx);
 7629                }
 7630            }
 7631        }
 7632    }
 7633
 7634    fn discard_edit_prediction(
 7635        &mut self,
 7636        should_report_edit_prediction_event: bool,
 7637        cx: &mut Context<Self>,
 7638    ) -> bool {
 7639        if should_report_edit_prediction_event {
 7640            let completion_id = self
 7641                .active_edit_prediction
 7642                .as_ref()
 7643                .and_then(|active_completion| active_completion.completion_id.clone());
 7644
 7645            self.report_edit_prediction_event(completion_id, false, cx);
 7646        }
 7647
 7648        if let Some(provider) = self.edit_prediction_provider() {
 7649            provider.discard(cx);
 7650        }
 7651
 7652        self.take_active_edit_prediction(cx)
 7653    }
 7654
 7655    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7656        let Some(provider) = self.edit_prediction_provider() else {
 7657            return;
 7658        };
 7659
 7660        let Some((_, buffer, _)) = self
 7661            .buffer
 7662            .read(cx)
 7663            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7664        else {
 7665            return;
 7666        };
 7667
 7668        let extension = buffer
 7669            .read(cx)
 7670            .file()
 7671            .and_then(|file| Some(file.path().extension()?.to_string()));
 7672
 7673        let event_type = match accepted {
 7674            true => "Edit Prediction Accepted",
 7675            false => "Edit Prediction Discarded",
 7676        };
 7677        telemetry::event!(
 7678            event_type,
 7679            provider = provider.name(),
 7680            prediction_id = id,
 7681            suggestion_accepted = accepted,
 7682            file_extension = extension,
 7683        );
 7684    }
 7685
 7686    fn open_editor_at_anchor(
 7687        snapshot: &language::BufferSnapshot,
 7688        target: language::Anchor,
 7689        workspace: &Entity<Workspace>,
 7690        window: &mut Window,
 7691        cx: &mut App,
 7692    ) -> Task<Result<()>> {
 7693        workspace.update(cx, |workspace, cx| {
 7694            let path = snapshot.file().map(|file| file.full_path(cx));
 7695            let Some(path) =
 7696                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7697            else {
 7698                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7699            };
 7700            let target = text::ToPoint::to_point(&target, snapshot);
 7701            let item = workspace.open_path(path, None, true, window, cx);
 7702            window.spawn(cx, async move |cx| {
 7703                let Some(editor) = item.await?.downcast::<Editor>() else {
 7704                    return Ok(());
 7705                };
 7706                editor
 7707                    .update_in(cx, |editor, window, cx| {
 7708                        editor.go_to_singleton_buffer_point(target, window, cx);
 7709                    })
 7710                    .ok();
 7711                anyhow::Ok(())
 7712            })
 7713        })
 7714    }
 7715
 7716    pub fn has_active_edit_prediction(&self) -> bool {
 7717        self.active_edit_prediction.is_some()
 7718    }
 7719
 7720    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7721        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7722            return false;
 7723        };
 7724
 7725        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7726        self.clear_highlights::<EditPredictionHighlight>(cx);
 7727        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7728        true
 7729    }
 7730
 7731    /// Returns true when we're displaying the edit prediction popover below the cursor
 7732    /// like we are not previewing and the LSP autocomplete menu is visible
 7733    /// or we are in `when_holding_modifier` mode.
 7734    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7735        if self.edit_prediction_preview_is_active()
 7736            || !self.show_edit_predictions_in_menu()
 7737            || !self.edit_predictions_enabled()
 7738        {
 7739            return false;
 7740        }
 7741
 7742        if self.has_visible_completions_menu() {
 7743            return true;
 7744        }
 7745
 7746        has_completion && self.edit_prediction_requires_modifier()
 7747    }
 7748
 7749    fn handle_modifiers_changed(
 7750        &mut self,
 7751        modifiers: Modifiers,
 7752        position_map: &PositionMap,
 7753        window: &mut Window,
 7754        cx: &mut Context<Self>,
 7755    ) {
 7756        if self.show_edit_predictions_in_menu() {
 7757            self.update_edit_prediction_preview(&modifiers, window, cx);
 7758        }
 7759
 7760        self.update_selection_mode(&modifiers, position_map, window, cx);
 7761
 7762        let mouse_position = window.mouse_position();
 7763        if !position_map.text_hitbox.is_hovered(window) {
 7764            return;
 7765        }
 7766
 7767        self.update_hovered_link(
 7768            position_map.point_for_position(mouse_position),
 7769            &position_map.snapshot,
 7770            modifiers,
 7771            window,
 7772            cx,
 7773        )
 7774    }
 7775
 7776    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7777        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7778        if invert {
 7779            match multi_cursor_setting {
 7780                MultiCursorModifier::Alt => modifiers.alt,
 7781                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7782            }
 7783        } else {
 7784            match multi_cursor_setting {
 7785                MultiCursorModifier::Alt => modifiers.secondary(),
 7786                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7787            }
 7788        }
 7789    }
 7790
 7791    fn columnar_selection_mode(
 7792        modifiers: &Modifiers,
 7793        cx: &mut Context<Self>,
 7794    ) -> Option<ColumnarMode> {
 7795        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7796            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7797                Some(ColumnarMode::FromMouse)
 7798            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7799                Some(ColumnarMode::FromSelection)
 7800            } else {
 7801                None
 7802            }
 7803        } else {
 7804            None
 7805        }
 7806    }
 7807
 7808    fn update_selection_mode(
 7809        &mut self,
 7810        modifiers: &Modifiers,
 7811        position_map: &PositionMap,
 7812        window: &mut Window,
 7813        cx: &mut Context<Self>,
 7814    ) {
 7815        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7816            return;
 7817        };
 7818        if self.selections.pending_anchor().is_none() {
 7819            return;
 7820        }
 7821
 7822        let mouse_position = window.mouse_position();
 7823        let point_for_position = position_map.point_for_position(mouse_position);
 7824        let position = point_for_position.previous_valid;
 7825
 7826        self.select(
 7827            SelectPhase::BeginColumnar {
 7828                position,
 7829                reset: false,
 7830                mode,
 7831                goal_column: point_for_position.exact_unclipped.column(),
 7832            },
 7833            window,
 7834            cx,
 7835        );
 7836    }
 7837
 7838    fn update_edit_prediction_preview(
 7839        &mut self,
 7840        modifiers: &Modifiers,
 7841        window: &mut Window,
 7842        cx: &mut Context<Self>,
 7843    ) {
 7844        let mut modifiers_held = false;
 7845        if let Some(accept_keystroke) = self
 7846            .accept_edit_prediction_keybind(false, window, cx)
 7847            .keystroke()
 7848        {
 7849            modifiers_held = modifiers_held
 7850                || (accept_keystroke.modifiers() == modifiers
 7851                    && accept_keystroke.modifiers().modified());
 7852        };
 7853        if let Some(accept_partial_keystroke) = self
 7854            .accept_edit_prediction_keybind(true, window, cx)
 7855            .keystroke()
 7856        {
 7857            modifiers_held = modifiers_held
 7858                || (accept_partial_keystroke.modifiers() == modifiers
 7859                    && accept_partial_keystroke.modifiers().modified());
 7860        }
 7861
 7862        if modifiers_held {
 7863            if matches!(
 7864                self.edit_prediction_preview,
 7865                EditPredictionPreview::Inactive { .. }
 7866            ) {
 7867                self.edit_prediction_preview = EditPredictionPreview::Active {
 7868                    previous_scroll_position: None,
 7869                    since: Instant::now(),
 7870                };
 7871
 7872                self.update_visible_edit_prediction(window, cx);
 7873                cx.notify();
 7874            }
 7875        } else if let EditPredictionPreview::Active {
 7876            previous_scroll_position,
 7877            since,
 7878        } = self.edit_prediction_preview
 7879        {
 7880            if let (Some(previous_scroll_position), Some(position_map)) =
 7881                (previous_scroll_position, self.last_position_map.as_ref())
 7882            {
 7883                self.set_scroll_position(
 7884                    previous_scroll_position
 7885                        .scroll_position(&position_map.snapshot.display_snapshot),
 7886                    window,
 7887                    cx,
 7888                );
 7889            }
 7890
 7891            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7892                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7893            };
 7894            self.clear_row_highlights::<EditPredictionPreview>();
 7895            self.update_visible_edit_prediction(window, cx);
 7896            cx.notify();
 7897        }
 7898    }
 7899
 7900    fn update_visible_edit_prediction(
 7901        &mut self,
 7902        _window: &mut Window,
 7903        cx: &mut Context<Self>,
 7904    ) -> Option<()> {
 7905        if DisableAiSettings::get_global(cx).disable_ai {
 7906            return None;
 7907        }
 7908
 7909        if self.ime_transaction.is_some() {
 7910            self.discard_edit_prediction(false, cx);
 7911            return None;
 7912        }
 7913
 7914        let selection = self.selections.newest_anchor();
 7915        let cursor = selection.head();
 7916        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7917        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7918        let excerpt_id = cursor.excerpt_id;
 7919
 7920        let show_in_menu = self.show_edit_predictions_in_menu();
 7921        let completions_menu_has_precedence = !show_in_menu
 7922            && (self.context_menu.borrow().is_some()
 7923                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7924
 7925        if completions_menu_has_precedence
 7926            || !offset_selection.is_empty()
 7927            || self
 7928                .active_edit_prediction
 7929                .as_ref()
 7930                .is_some_and(|completion| {
 7931                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7932                        return false;
 7933                    };
 7934                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7935                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7936                    !invalidation_range.contains(&offset_selection.head())
 7937                })
 7938        {
 7939            self.discard_edit_prediction(false, cx);
 7940            return None;
 7941        }
 7942
 7943        self.take_active_edit_prediction(cx);
 7944        let Some(provider) = self.edit_prediction_provider() else {
 7945            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7946            return None;
 7947        };
 7948
 7949        let (buffer, cursor_buffer_position) =
 7950            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7951
 7952        self.edit_prediction_settings =
 7953            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7954
 7955        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7956
 7957        if self.edit_prediction_indent_conflict {
 7958            let cursor_point = cursor.to_point(&multibuffer);
 7959
 7960            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7961
 7962            if let Some((_, indent)) = indents.iter().next()
 7963                && indent.len == cursor_point.column
 7964            {
 7965                self.edit_prediction_indent_conflict = false;
 7966            }
 7967        }
 7968
 7969        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7970
 7971        let (completion_id, edits, edit_preview) = match edit_prediction {
 7972            edit_prediction::EditPrediction::Local {
 7973                id,
 7974                edits,
 7975                edit_preview,
 7976            } => (id, edits, edit_preview),
 7977            edit_prediction::EditPrediction::Jump {
 7978                id,
 7979                snapshot,
 7980                target,
 7981            } => {
 7982                self.stale_edit_prediction_in_menu = None;
 7983                self.active_edit_prediction = Some(EditPredictionState {
 7984                    inlay_ids: vec![],
 7985                    completion: EditPrediction::MoveOutside { snapshot, target },
 7986                    completion_id: id,
 7987                    invalidation_range: None,
 7988                });
 7989                cx.notify();
 7990                return Some(());
 7991            }
 7992        };
 7993
 7994        let edits = edits
 7995            .into_iter()
 7996            .flat_map(|(range, new_text)| {
 7997                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7998                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7999                Some((start..end, new_text))
 8000            })
 8001            .collect::<Vec<_>>();
 8002        if edits.is_empty() {
 8003            return None;
 8004        }
 8005
 8006        let first_edit_start = edits.first().unwrap().0.start;
 8007        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8008        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8009
 8010        let last_edit_end = edits.last().unwrap().0.end;
 8011        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8012        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8013
 8014        let cursor_row = cursor.to_point(&multibuffer).row;
 8015
 8016        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8017
 8018        let mut inlay_ids = Vec::new();
 8019        let invalidation_row_range;
 8020        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8021            Some(cursor_row..edit_end_row)
 8022        } else if cursor_row > edit_end_row {
 8023            Some(edit_start_row..cursor_row)
 8024        } else {
 8025            None
 8026        };
 8027        let supports_jump = self
 8028            .edit_prediction_provider
 8029            .as_ref()
 8030            .map(|provider| provider.provider.supports_jump_to_edit())
 8031            .unwrap_or(true);
 8032
 8033        let is_move = supports_jump
 8034            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8035        let completion = if is_move {
 8036            invalidation_row_range =
 8037                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8038            let target = first_edit_start;
 8039            EditPrediction::MoveWithin { target, snapshot }
 8040        } else {
 8041            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8042                && !self.edit_predictions_hidden_for_vim_mode;
 8043
 8044            if show_completions_in_buffer {
 8045                if edits
 8046                    .iter()
 8047                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8048                {
 8049                    let mut inlays = Vec::new();
 8050                    for (range, new_text) in &edits {
 8051                        let inlay = Inlay::edit_prediction(
 8052                            post_inc(&mut self.next_inlay_id),
 8053                            range.start,
 8054                            new_text.as_str(),
 8055                        );
 8056                        inlay_ids.push(inlay.id);
 8057                        inlays.push(inlay);
 8058                    }
 8059
 8060                    self.splice_inlays(&[], inlays, cx);
 8061                } else {
 8062                    let background_color = cx.theme().status().deleted_background;
 8063                    self.highlight_text::<EditPredictionHighlight>(
 8064                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8065                        HighlightStyle {
 8066                            background_color: Some(background_color),
 8067                            ..Default::default()
 8068                        },
 8069                        cx,
 8070                    );
 8071                }
 8072            }
 8073
 8074            invalidation_row_range = edit_start_row..edit_end_row;
 8075
 8076            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8077                if provider.show_tab_accept_marker() {
 8078                    EditDisplayMode::TabAccept
 8079                } else {
 8080                    EditDisplayMode::Inline
 8081                }
 8082            } else {
 8083                EditDisplayMode::DiffPopover
 8084            };
 8085
 8086            EditPrediction::Edit {
 8087                edits,
 8088                edit_preview,
 8089                display_mode,
 8090                snapshot,
 8091            }
 8092        };
 8093
 8094        let invalidation_range = multibuffer
 8095            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8096            ..multibuffer.anchor_after(Point::new(
 8097                invalidation_row_range.end,
 8098                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8099            ));
 8100
 8101        self.stale_edit_prediction_in_menu = None;
 8102        self.active_edit_prediction = Some(EditPredictionState {
 8103            inlay_ids,
 8104            completion,
 8105            completion_id,
 8106            invalidation_range: Some(invalidation_range),
 8107        });
 8108
 8109        cx.notify();
 8110
 8111        Some(())
 8112    }
 8113
 8114    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8115        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8116    }
 8117
 8118    fn clear_tasks(&mut self) {
 8119        self.tasks.clear()
 8120    }
 8121
 8122    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8123        if self.tasks.insert(key, value).is_some() {
 8124            // This case should hopefully be rare, but just in case...
 8125            log::error!(
 8126                "multiple different run targets found on a single line, only the last target will be rendered"
 8127            )
 8128        }
 8129    }
 8130
 8131    /// Get all display points of breakpoints that will be rendered within editor
 8132    ///
 8133    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8134    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8135    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8136    fn active_breakpoints(
 8137        &self,
 8138        range: Range<DisplayRow>,
 8139        window: &mut Window,
 8140        cx: &mut Context<Self>,
 8141    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8142        let mut breakpoint_display_points = HashMap::default();
 8143
 8144        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8145            return breakpoint_display_points;
 8146        };
 8147
 8148        let snapshot = self.snapshot(window, cx);
 8149
 8150        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8151        let Some(project) = self.project() else {
 8152            return breakpoint_display_points;
 8153        };
 8154
 8155        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8156            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8157
 8158        for (buffer_snapshot, range, excerpt_id) in
 8159            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8160        {
 8161            let Some(buffer) = project
 8162                .read(cx)
 8163                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8164            else {
 8165                continue;
 8166            };
 8167            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8168                &buffer,
 8169                Some(
 8170                    buffer_snapshot.anchor_before(range.start)
 8171                        ..buffer_snapshot.anchor_after(range.end),
 8172                ),
 8173                buffer_snapshot,
 8174                cx,
 8175            );
 8176            for (breakpoint, state) in breakpoints {
 8177                let multi_buffer_anchor =
 8178                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8179                let position = multi_buffer_anchor
 8180                    .to_point(multi_buffer_snapshot)
 8181                    .to_display_point(&snapshot);
 8182
 8183                breakpoint_display_points.insert(
 8184                    position.row(),
 8185                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8186                );
 8187            }
 8188        }
 8189
 8190        breakpoint_display_points
 8191    }
 8192
 8193    fn breakpoint_context_menu(
 8194        &self,
 8195        anchor: Anchor,
 8196        window: &mut Window,
 8197        cx: &mut Context<Self>,
 8198    ) -> Entity<ui::ContextMenu> {
 8199        let weak_editor = cx.weak_entity();
 8200        let focus_handle = self.focus_handle(cx);
 8201
 8202        let row = self
 8203            .buffer
 8204            .read(cx)
 8205            .snapshot(cx)
 8206            .summary_for_anchor::<Point>(&anchor)
 8207            .row;
 8208
 8209        let breakpoint = self
 8210            .breakpoint_at_row(row, window, cx)
 8211            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8212
 8213        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8214            "Edit Log Breakpoint"
 8215        } else {
 8216            "Set Log Breakpoint"
 8217        };
 8218
 8219        let condition_breakpoint_msg = if breakpoint
 8220            .as_ref()
 8221            .is_some_and(|bp| bp.1.condition.is_some())
 8222        {
 8223            "Edit Condition Breakpoint"
 8224        } else {
 8225            "Set Condition Breakpoint"
 8226        };
 8227
 8228        let hit_condition_breakpoint_msg = if breakpoint
 8229            .as_ref()
 8230            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8231        {
 8232            "Edit Hit Condition Breakpoint"
 8233        } else {
 8234            "Set Hit Condition Breakpoint"
 8235        };
 8236
 8237        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8238            "Unset Breakpoint"
 8239        } else {
 8240            "Set Breakpoint"
 8241        };
 8242
 8243        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8244
 8245        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8246            BreakpointState::Enabled => Some("Disable"),
 8247            BreakpointState::Disabled => Some("Enable"),
 8248        });
 8249
 8250        let (anchor, breakpoint) =
 8251            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8252
 8253        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8254            menu.on_blur_subscription(Subscription::new(|| {}))
 8255                .context(focus_handle)
 8256                .when(run_to_cursor, |this| {
 8257                    let weak_editor = weak_editor.clone();
 8258                    this.entry("Run to cursor", None, move |window, cx| {
 8259                        weak_editor
 8260                            .update(cx, |editor, cx| {
 8261                                editor.change_selections(
 8262                                    SelectionEffects::no_scroll(),
 8263                                    window,
 8264                                    cx,
 8265                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8266                                );
 8267                            })
 8268                            .ok();
 8269
 8270                        window.dispatch_action(Box::new(RunToCursor), cx);
 8271                    })
 8272                    .separator()
 8273                })
 8274                .when_some(toggle_state_msg, |this, msg| {
 8275                    this.entry(msg, None, {
 8276                        let weak_editor = weak_editor.clone();
 8277                        let breakpoint = breakpoint.clone();
 8278                        move |_window, cx| {
 8279                            weak_editor
 8280                                .update(cx, |this, cx| {
 8281                                    this.edit_breakpoint_at_anchor(
 8282                                        anchor,
 8283                                        breakpoint.as_ref().clone(),
 8284                                        BreakpointEditAction::InvertState,
 8285                                        cx,
 8286                                    );
 8287                                })
 8288                                .log_err();
 8289                        }
 8290                    })
 8291                })
 8292                .entry(set_breakpoint_msg, None, {
 8293                    let weak_editor = weak_editor.clone();
 8294                    let breakpoint = breakpoint.clone();
 8295                    move |_window, cx| {
 8296                        weak_editor
 8297                            .update(cx, |this, cx| {
 8298                                this.edit_breakpoint_at_anchor(
 8299                                    anchor,
 8300                                    breakpoint.as_ref().clone(),
 8301                                    BreakpointEditAction::Toggle,
 8302                                    cx,
 8303                                );
 8304                            })
 8305                            .log_err();
 8306                    }
 8307                })
 8308                .entry(log_breakpoint_msg, None, {
 8309                    let breakpoint = breakpoint.clone();
 8310                    let weak_editor = weak_editor.clone();
 8311                    move |window, cx| {
 8312                        weak_editor
 8313                            .update(cx, |this, cx| {
 8314                                this.add_edit_breakpoint_block(
 8315                                    anchor,
 8316                                    breakpoint.as_ref(),
 8317                                    BreakpointPromptEditAction::Log,
 8318                                    window,
 8319                                    cx,
 8320                                );
 8321                            })
 8322                            .log_err();
 8323                    }
 8324                })
 8325                .entry(condition_breakpoint_msg, None, {
 8326                    let breakpoint = breakpoint.clone();
 8327                    let weak_editor = weak_editor.clone();
 8328                    move |window, cx| {
 8329                        weak_editor
 8330                            .update(cx, |this, cx| {
 8331                                this.add_edit_breakpoint_block(
 8332                                    anchor,
 8333                                    breakpoint.as_ref(),
 8334                                    BreakpointPromptEditAction::Condition,
 8335                                    window,
 8336                                    cx,
 8337                                );
 8338                            })
 8339                            .log_err();
 8340                    }
 8341                })
 8342                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8343                    weak_editor
 8344                        .update(cx, |this, cx| {
 8345                            this.add_edit_breakpoint_block(
 8346                                anchor,
 8347                                breakpoint.as_ref(),
 8348                                BreakpointPromptEditAction::HitCondition,
 8349                                window,
 8350                                cx,
 8351                            );
 8352                        })
 8353                        .log_err();
 8354                })
 8355        })
 8356    }
 8357
 8358    fn render_breakpoint(
 8359        &self,
 8360        position: Anchor,
 8361        row: DisplayRow,
 8362        breakpoint: &Breakpoint,
 8363        state: Option<BreakpointSessionState>,
 8364        cx: &mut Context<Self>,
 8365    ) -> IconButton {
 8366        let is_rejected = state.is_some_and(|s| !s.verified);
 8367        // Is it a breakpoint that shows up when hovering over gutter?
 8368        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8369            (false, false),
 8370            |PhantomBreakpointIndicator {
 8371                 is_active,
 8372                 display_row,
 8373                 collides_with_existing_breakpoint,
 8374             }| {
 8375                (
 8376                    is_active && display_row == row,
 8377                    collides_with_existing_breakpoint,
 8378                )
 8379            },
 8380        );
 8381
 8382        let (color, icon) = {
 8383            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8384                (false, false) => ui::IconName::DebugBreakpoint,
 8385                (true, false) => ui::IconName::DebugLogBreakpoint,
 8386                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8387                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8388            };
 8389
 8390            let color = if is_phantom {
 8391                Color::Hint
 8392            } else if is_rejected {
 8393                Color::Disabled
 8394            } else {
 8395                Color::Debugger
 8396            };
 8397
 8398            (color, icon)
 8399        };
 8400
 8401        let breakpoint = Arc::from(breakpoint.clone());
 8402
 8403        let alt_as_text = gpui::Keystroke {
 8404            modifiers: Modifiers::secondary_key(),
 8405            ..Default::default()
 8406        };
 8407        let primary_action_text = if breakpoint.is_disabled() {
 8408            "Enable breakpoint"
 8409        } else if is_phantom && !collides_with_existing {
 8410            "Set breakpoint"
 8411        } else {
 8412            "Unset breakpoint"
 8413        };
 8414        let focus_handle = self.focus_handle.clone();
 8415
 8416        let meta = if is_rejected {
 8417            SharedString::from("No executable code is associated with this line.")
 8418        } else if collides_with_existing && !breakpoint.is_disabled() {
 8419            SharedString::from(format!(
 8420                "{alt_as_text}-click to disable,\nright-click for more options."
 8421            ))
 8422        } else {
 8423            SharedString::from("Right-click for more options.")
 8424        };
 8425        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8426            .icon_size(IconSize::XSmall)
 8427            .size(ui::ButtonSize::None)
 8428            .when(is_rejected, |this| {
 8429                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8430            })
 8431            .icon_color(color)
 8432            .style(ButtonStyle::Transparent)
 8433            .on_click(cx.listener({
 8434                move |editor, event: &ClickEvent, window, cx| {
 8435                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8436                        BreakpointEditAction::InvertState
 8437                    } else {
 8438                        BreakpointEditAction::Toggle
 8439                    };
 8440
 8441                    window.focus(&editor.focus_handle(cx));
 8442                    editor.edit_breakpoint_at_anchor(
 8443                        position,
 8444                        breakpoint.as_ref().clone(),
 8445                        edit_action,
 8446                        cx,
 8447                    );
 8448                }
 8449            }))
 8450            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8451                editor.set_breakpoint_context_menu(
 8452                    row,
 8453                    Some(position),
 8454                    event.position(),
 8455                    window,
 8456                    cx,
 8457                );
 8458            }))
 8459            .tooltip(move |window, cx| {
 8460                Tooltip::with_meta_in(
 8461                    primary_action_text,
 8462                    Some(&ToggleBreakpoint),
 8463                    meta.clone(),
 8464                    &focus_handle,
 8465                    window,
 8466                    cx,
 8467                )
 8468            })
 8469    }
 8470
 8471    fn build_tasks_context(
 8472        project: &Entity<Project>,
 8473        buffer: &Entity<Buffer>,
 8474        buffer_row: u32,
 8475        tasks: &Arc<RunnableTasks>,
 8476        cx: &mut Context<Self>,
 8477    ) -> Task<Option<task::TaskContext>> {
 8478        let position = Point::new(buffer_row, tasks.column);
 8479        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8480        let location = Location {
 8481            buffer: buffer.clone(),
 8482            range: range_start..range_start,
 8483        };
 8484        // Fill in the environmental variables from the tree-sitter captures
 8485        let mut captured_task_variables = TaskVariables::default();
 8486        for (capture_name, value) in tasks.extra_variables.clone() {
 8487            captured_task_variables.insert(
 8488                task::VariableName::Custom(capture_name.into()),
 8489                value.clone(),
 8490            );
 8491        }
 8492        project.update(cx, |project, cx| {
 8493            project.task_store().update(cx, |task_store, cx| {
 8494                task_store.task_context_for_location(captured_task_variables, location, cx)
 8495            })
 8496        })
 8497    }
 8498
 8499    pub fn spawn_nearest_task(
 8500        &mut self,
 8501        action: &SpawnNearestTask,
 8502        window: &mut Window,
 8503        cx: &mut Context<Self>,
 8504    ) {
 8505        let Some((workspace, _)) = self.workspace.clone() else {
 8506            return;
 8507        };
 8508        let Some(project) = self.project.clone() else {
 8509            return;
 8510        };
 8511
 8512        // Try to find a closest, enclosing node using tree-sitter that has a task
 8513        let Some((buffer, buffer_row, tasks)) = self
 8514            .find_enclosing_node_task(cx)
 8515            // Or find the task that's closest in row-distance.
 8516            .or_else(|| self.find_closest_task(cx))
 8517        else {
 8518            return;
 8519        };
 8520
 8521        let reveal_strategy = action.reveal;
 8522        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8523        cx.spawn_in(window, async move |_, cx| {
 8524            let context = task_context.await?;
 8525            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8526
 8527            let resolved = &mut resolved_task.resolved;
 8528            resolved.reveal = reveal_strategy;
 8529
 8530            workspace
 8531                .update_in(cx, |workspace, window, cx| {
 8532                    workspace.schedule_resolved_task(
 8533                        task_source_kind,
 8534                        resolved_task,
 8535                        false,
 8536                        window,
 8537                        cx,
 8538                    );
 8539                })
 8540                .ok()
 8541        })
 8542        .detach();
 8543    }
 8544
 8545    fn find_closest_task(
 8546        &mut self,
 8547        cx: &mut Context<Self>,
 8548    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8549        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8550
 8551        let ((buffer_id, row), tasks) = self
 8552            .tasks
 8553            .iter()
 8554            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8555
 8556        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8557        let tasks = Arc::new(tasks.to_owned());
 8558        Some((buffer, *row, tasks))
 8559    }
 8560
 8561    fn find_enclosing_node_task(
 8562        &mut self,
 8563        cx: &mut Context<Self>,
 8564    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8565        let snapshot = self.buffer.read(cx).snapshot(cx);
 8566        let offset = self.selections.newest::<usize>(cx).head();
 8567        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8568        let buffer_id = excerpt.buffer().remote_id();
 8569
 8570        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8571        let mut cursor = layer.node().walk();
 8572
 8573        while cursor.goto_first_child_for_byte(offset).is_some() {
 8574            if cursor.node().end_byte() == offset {
 8575                cursor.goto_next_sibling();
 8576            }
 8577        }
 8578
 8579        // Ascend to the smallest ancestor that contains the range and has a task.
 8580        loop {
 8581            let node = cursor.node();
 8582            let node_range = node.byte_range();
 8583            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8584
 8585            // Check if this node contains our offset
 8586            if node_range.start <= offset && node_range.end >= offset {
 8587                // If it contains offset, check for task
 8588                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8589                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8590                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8591                }
 8592            }
 8593
 8594            if !cursor.goto_parent() {
 8595                break;
 8596            }
 8597        }
 8598        None
 8599    }
 8600
 8601    fn render_run_indicator(
 8602        &self,
 8603        _style: &EditorStyle,
 8604        is_active: bool,
 8605        row: DisplayRow,
 8606        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8607        cx: &mut Context<Self>,
 8608    ) -> IconButton {
 8609        let color = Color::Muted;
 8610        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8611
 8612        IconButton::new(
 8613            ("run_indicator", row.0 as usize),
 8614            ui::IconName::PlayOutlined,
 8615        )
 8616        .shape(ui::IconButtonShape::Square)
 8617        .icon_size(IconSize::XSmall)
 8618        .icon_color(color)
 8619        .toggle_state(is_active)
 8620        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8621            let quick_launch = match e {
 8622                ClickEvent::Keyboard(_) => true,
 8623                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8624            };
 8625
 8626            window.focus(&editor.focus_handle(cx));
 8627            editor.toggle_code_actions(
 8628                &ToggleCodeActions {
 8629                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8630                    quick_launch,
 8631                },
 8632                window,
 8633                cx,
 8634            );
 8635        }))
 8636        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8637            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8638        }))
 8639    }
 8640
 8641    pub fn context_menu_visible(&self) -> bool {
 8642        !self.edit_prediction_preview_is_active()
 8643            && self
 8644                .context_menu
 8645                .borrow()
 8646                .as_ref()
 8647                .is_some_and(|menu| menu.visible())
 8648    }
 8649
 8650    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8651        self.context_menu
 8652            .borrow()
 8653            .as_ref()
 8654            .map(|menu| menu.origin())
 8655    }
 8656
 8657    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8658        self.context_menu_options = Some(options);
 8659    }
 8660
 8661    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8662    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8663
 8664    fn render_edit_prediction_popover(
 8665        &mut self,
 8666        text_bounds: &Bounds<Pixels>,
 8667        content_origin: gpui::Point<Pixels>,
 8668        right_margin: Pixels,
 8669        editor_snapshot: &EditorSnapshot,
 8670        visible_row_range: Range<DisplayRow>,
 8671        scroll_top: ScrollOffset,
 8672        scroll_bottom: ScrollOffset,
 8673        line_layouts: &[LineWithInvisibles],
 8674        line_height: Pixels,
 8675        scroll_position: gpui::Point<ScrollOffset>,
 8676        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8677        newest_selection_head: Option<DisplayPoint>,
 8678        editor_width: Pixels,
 8679        style: &EditorStyle,
 8680        window: &mut Window,
 8681        cx: &mut App,
 8682    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8683        if self.mode().is_minimap() {
 8684            return None;
 8685        }
 8686        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8687
 8688        if self.edit_prediction_visible_in_cursor_popover(true) {
 8689            return None;
 8690        }
 8691
 8692        match &active_edit_prediction.completion {
 8693            EditPrediction::MoveWithin { target, .. } => {
 8694                let target_display_point = target.to_display_point(editor_snapshot);
 8695
 8696                if self.edit_prediction_requires_modifier() {
 8697                    if !self.edit_prediction_preview_is_active() {
 8698                        return None;
 8699                    }
 8700
 8701                    self.render_edit_prediction_modifier_jump_popover(
 8702                        text_bounds,
 8703                        content_origin,
 8704                        visible_row_range,
 8705                        line_layouts,
 8706                        line_height,
 8707                        scroll_pixel_position,
 8708                        newest_selection_head,
 8709                        target_display_point,
 8710                        window,
 8711                        cx,
 8712                    )
 8713                } else {
 8714                    self.render_edit_prediction_eager_jump_popover(
 8715                        text_bounds,
 8716                        content_origin,
 8717                        editor_snapshot,
 8718                        visible_row_range,
 8719                        scroll_top,
 8720                        scroll_bottom,
 8721                        line_height,
 8722                        scroll_pixel_position,
 8723                        target_display_point,
 8724                        editor_width,
 8725                        window,
 8726                        cx,
 8727                    )
 8728                }
 8729            }
 8730            EditPrediction::Edit {
 8731                display_mode: EditDisplayMode::Inline,
 8732                ..
 8733            } => None,
 8734            EditPrediction::Edit {
 8735                display_mode: EditDisplayMode::TabAccept,
 8736                edits,
 8737                ..
 8738            } => {
 8739                let range = &edits.first()?.0;
 8740                let target_display_point = range.end.to_display_point(editor_snapshot);
 8741
 8742                self.render_edit_prediction_end_of_line_popover(
 8743                    "Accept",
 8744                    editor_snapshot,
 8745                    visible_row_range,
 8746                    target_display_point,
 8747                    line_height,
 8748                    scroll_pixel_position,
 8749                    content_origin,
 8750                    editor_width,
 8751                    window,
 8752                    cx,
 8753                )
 8754            }
 8755            EditPrediction::Edit {
 8756                edits,
 8757                edit_preview,
 8758                display_mode: EditDisplayMode::DiffPopover,
 8759                snapshot,
 8760            } => self.render_edit_prediction_diff_popover(
 8761                text_bounds,
 8762                content_origin,
 8763                right_margin,
 8764                editor_snapshot,
 8765                visible_row_range,
 8766                line_layouts,
 8767                line_height,
 8768                scroll_position,
 8769                scroll_pixel_position,
 8770                newest_selection_head,
 8771                editor_width,
 8772                style,
 8773                edits,
 8774                edit_preview,
 8775                snapshot,
 8776                window,
 8777                cx,
 8778            ),
 8779            EditPrediction::MoveOutside { snapshot, .. } => {
 8780                let file_name = snapshot
 8781                    .file()
 8782                    .map(|file| file.file_name(cx))
 8783                    .unwrap_or("untitled");
 8784                let mut element = self
 8785                    .render_edit_prediction_line_popover(
 8786                        format!("Jump to {file_name}"),
 8787                        Some(IconName::ZedPredict),
 8788                        window,
 8789                        cx,
 8790                    )
 8791                    .into_any();
 8792
 8793                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8794                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8795                let origin_y = text_bounds.size.height - size.height - px(30.);
 8796                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8797                element.prepaint_at(origin, window, cx);
 8798
 8799                Some((element, origin))
 8800            }
 8801        }
 8802    }
 8803
 8804    fn render_edit_prediction_modifier_jump_popover(
 8805        &mut self,
 8806        text_bounds: &Bounds<Pixels>,
 8807        content_origin: gpui::Point<Pixels>,
 8808        visible_row_range: Range<DisplayRow>,
 8809        line_layouts: &[LineWithInvisibles],
 8810        line_height: Pixels,
 8811        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8812        newest_selection_head: Option<DisplayPoint>,
 8813        target_display_point: DisplayPoint,
 8814        window: &mut Window,
 8815        cx: &mut App,
 8816    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8817        let scrolled_content_origin =
 8818            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8819
 8820        const SCROLL_PADDING_Y: Pixels = px(12.);
 8821
 8822        if target_display_point.row() < visible_row_range.start {
 8823            return self.render_edit_prediction_scroll_popover(
 8824                |_| SCROLL_PADDING_Y,
 8825                IconName::ArrowUp,
 8826                visible_row_range,
 8827                line_layouts,
 8828                newest_selection_head,
 8829                scrolled_content_origin,
 8830                window,
 8831                cx,
 8832            );
 8833        } else if target_display_point.row() >= visible_row_range.end {
 8834            return self.render_edit_prediction_scroll_popover(
 8835                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8836                IconName::ArrowDown,
 8837                visible_row_range,
 8838                line_layouts,
 8839                newest_selection_head,
 8840                scrolled_content_origin,
 8841                window,
 8842                cx,
 8843            );
 8844        }
 8845
 8846        const POLE_WIDTH: Pixels = px(2.);
 8847
 8848        let line_layout =
 8849            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8850        let target_column = target_display_point.column() as usize;
 8851
 8852        let target_x = line_layout.x_for_index(target_column);
 8853        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8854            - scroll_pixel_position.y;
 8855
 8856        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8857
 8858        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8859        border_color.l += 0.001;
 8860
 8861        let mut element = v_flex()
 8862            .items_end()
 8863            .when(flag_on_right, |el| el.items_start())
 8864            .child(if flag_on_right {
 8865                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8866                    .rounded_bl(px(0.))
 8867                    .rounded_tl(px(0.))
 8868                    .border_l_2()
 8869                    .border_color(border_color)
 8870            } else {
 8871                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8872                    .rounded_br(px(0.))
 8873                    .rounded_tr(px(0.))
 8874                    .border_r_2()
 8875                    .border_color(border_color)
 8876            })
 8877            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8878            .into_any();
 8879
 8880        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8881
 8882        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8883            - point(
 8884                if flag_on_right {
 8885                    POLE_WIDTH
 8886                } else {
 8887                    size.width - POLE_WIDTH
 8888                },
 8889                size.height - line_height,
 8890            );
 8891
 8892        origin.x = origin.x.max(content_origin.x);
 8893
 8894        element.prepaint_at(origin, window, cx);
 8895
 8896        Some((element, origin))
 8897    }
 8898
 8899    fn render_edit_prediction_scroll_popover(
 8900        &mut self,
 8901        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8902        scroll_icon: IconName,
 8903        visible_row_range: Range<DisplayRow>,
 8904        line_layouts: &[LineWithInvisibles],
 8905        newest_selection_head: Option<DisplayPoint>,
 8906        scrolled_content_origin: gpui::Point<Pixels>,
 8907        window: &mut Window,
 8908        cx: &mut App,
 8909    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8910        let mut element = self
 8911            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8912            .into_any();
 8913
 8914        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8915
 8916        let cursor = newest_selection_head?;
 8917        let cursor_row_layout =
 8918            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8919        let cursor_column = cursor.column() as usize;
 8920
 8921        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8922
 8923        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8924
 8925        element.prepaint_at(origin, window, cx);
 8926        Some((element, origin))
 8927    }
 8928
 8929    fn render_edit_prediction_eager_jump_popover(
 8930        &mut self,
 8931        text_bounds: &Bounds<Pixels>,
 8932        content_origin: gpui::Point<Pixels>,
 8933        editor_snapshot: &EditorSnapshot,
 8934        visible_row_range: Range<DisplayRow>,
 8935        scroll_top: ScrollOffset,
 8936        scroll_bottom: ScrollOffset,
 8937        line_height: Pixels,
 8938        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8939        target_display_point: DisplayPoint,
 8940        editor_width: Pixels,
 8941        window: &mut Window,
 8942        cx: &mut App,
 8943    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8944        if target_display_point.row().as_f64() < scroll_top {
 8945            let mut element = self
 8946                .render_edit_prediction_line_popover(
 8947                    "Jump to Edit",
 8948                    Some(IconName::ArrowUp),
 8949                    window,
 8950                    cx,
 8951                )
 8952                .into_any();
 8953
 8954            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8955            let offset = point(
 8956                (text_bounds.size.width - size.width) / 2.,
 8957                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8958            );
 8959
 8960            let origin = text_bounds.origin + offset;
 8961            element.prepaint_at(origin, window, cx);
 8962            Some((element, origin))
 8963        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8964            let mut element = self
 8965                .render_edit_prediction_line_popover(
 8966                    "Jump to Edit",
 8967                    Some(IconName::ArrowDown),
 8968                    window,
 8969                    cx,
 8970                )
 8971                .into_any();
 8972
 8973            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8974            let offset = point(
 8975                (text_bounds.size.width - size.width) / 2.,
 8976                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8977            );
 8978
 8979            let origin = text_bounds.origin + offset;
 8980            element.prepaint_at(origin, window, cx);
 8981            Some((element, origin))
 8982        } else {
 8983            self.render_edit_prediction_end_of_line_popover(
 8984                "Jump to Edit",
 8985                editor_snapshot,
 8986                visible_row_range,
 8987                target_display_point,
 8988                line_height,
 8989                scroll_pixel_position,
 8990                content_origin,
 8991                editor_width,
 8992                window,
 8993                cx,
 8994            )
 8995        }
 8996    }
 8997
 8998    fn render_edit_prediction_end_of_line_popover(
 8999        self: &mut Editor,
 9000        label: &'static str,
 9001        editor_snapshot: &EditorSnapshot,
 9002        visible_row_range: Range<DisplayRow>,
 9003        target_display_point: DisplayPoint,
 9004        line_height: Pixels,
 9005        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9006        content_origin: gpui::Point<Pixels>,
 9007        editor_width: Pixels,
 9008        window: &mut Window,
 9009        cx: &mut App,
 9010    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9011        let target_line_end = DisplayPoint::new(
 9012            target_display_point.row(),
 9013            editor_snapshot.line_len(target_display_point.row()),
 9014        );
 9015
 9016        let mut element = self
 9017            .render_edit_prediction_line_popover(label, None, window, cx)
 9018            .into_any();
 9019
 9020        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9021
 9022        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9023
 9024        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9025        let mut origin = start_point
 9026            + line_origin
 9027            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9028        origin.x = origin.x.max(content_origin.x);
 9029
 9030        let max_x = content_origin.x + editor_width - size.width;
 9031
 9032        if origin.x > max_x {
 9033            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9034
 9035            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9036                origin.y += offset;
 9037                IconName::ArrowUp
 9038            } else {
 9039                origin.y -= offset;
 9040                IconName::ArrowDown
 9041            };
 9042
 9043            element = self
 9044                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9045                .into_any();
 9046
 9047            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9048
 9049            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9050        }
 9051
 9052        element.prepaint_at(origin, window, cx);
 9053        Some((element, origin))
 9054    }
 9055
 9056    fn render_edit_prediction_diff_popover(
 9057        self: &Editor,
 9058        text_bounds: &Bounds<Pixels>,
 9059        content_origin: gpui::Point<Pixels>,
 9060        right_margin: Pixels,
 9061        editor_snapshot: &EditorSnapshot,
 9062        visible_row_range: Range<DisplayRow>,
 9063        line_layouts: &[LineWithInvisibles],
 9064        line_height: Pixels,
 9065        scroll_position: gpui::Point<ScrollOffset>,
 9066        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9067        newest_selection_head: Option<DisplayPoint>,
 9068        editor_width: Pixels,
 9069        style: &EditorStyle,
 9070        edits: &Vec<(Range<Anchor>, String)>,
 9071        edit_preview: &Option<language::EditPreview>,
 9072        snapshot: &language::BufferSnapshot,
 9073        window: &mut Window,
 9074        cx: &mut App,
 9075    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9076        let edit_start = edits
 9077            .first()
 9078            .unwrap()
 9079            .0
 9080            .start
 9081            .to_display_point(editor_snapshot);
 9082        let edit_end = edits
 9083            .last()
 9084            .unwrap()
 9085            .0
 9086            .end
 9087            .to_display_point(editor_snapshot);
 9088
 9089        let is_visible = visible_row_range.contains(&edit_start.row())
 9090            || visible_row_range.contains(&edit_end.row());
 9091        if !is_visible {
 9092            return None;
 9093        }
 9094
 9095        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9096            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9097        } else {
 9098            // Fallback for providers without edit_preview
 9099            crate::edit_prediction_fallback_text(edits, cx)
 9100        };
 9101
 9102        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9103        let line_count = highlighted_edits.text.lines().count();
 9104
 9105        const BORDER_WIDTH: Pixels = px(1.);
 9106
 9107        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9108        let has_keybind = keybind.is_some();
 9109
 9110        let mut element = h_flex()
 9111            .items_start()
 9112            .child(
 9113                h_flex()
 9114                    .bg(cx.theme().colors().editor_background)
 9115                    .border(BORDER_WIDTH)
 9116                    .shadow_xs()
 9117                    .border_color(cx.theme().colors().border)
 9118                    .rounded_l_lg()
 9119                    .when(line_count > 1, |el| el.rounded_br_lg())
 9120                    .pr_1()
 9121                    .child(styled_text),
 9122            )
 9123            .child(
 9124                h_flex()
 9125                    .h(line_height + BORDER_WIDTH * 2.)
 9126                    .px_1p5()
 9127                    .gap_1()
 9128                    // Workaround: For some reason, there's a gap if we don't do this
 9129                    .ml(-BORDER_WIDTH)
 9130                    .shadow(vec![gpui::BoxShadow {
 9131                        color: gpui::black().opacity(0.05),
 9132                        offset: point(px(1.), px(1.)),
 9133                        blur_radius: px(2.),
 9134                        spread_radius: px(0.),
 9135                    }])
 9136                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9137                    .border(BORDER_WIDTH)
 9138                    .border_color(cx.theme().colors().border)
 9139                    .rounded_r_lg()
 9140                    .id("edit_prediction_diff_popover_keybind")
 9141                    .when(!has_keybind, |el| {
 9142                        let status_colors = cx.theme().status();
 9143
 9144                        el.bg(status_colors.error_background)
 9145                            .border_color(status_colors.error.opacity(0.6))
 9146                            .child(Icon::new(IconName::Info).color(Color::Error))
 9147                            .cursor_default()
 9148                            .hoverable_tooltip(move |_window, cx| {
 9149                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9150                            })
 9151                    })
 9152                    .children(keybind),
 9153            )
 9154            .into_any();
 9155
 9156        let longest_row =
 9157            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9158        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9159            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9160        } else {
 9161            layout_line(
 9162                longest_row,
 9163                editor_snapshot,
 9164                style,
 9165                editor_width,
 9166                |_| false,
 9167                window,
 9168                cx,
 9169            )
 9170            .width
 9171        };
 9172
 9173        let viewport_bounds =
 9174            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9175                right: -right_margin,
 9176                ..Default::default()
 9177            });
 9178
 9179        let x_after_longest = Pixels::from(
 9180            ScrollPixelOffset::from(
 9181                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9182            ) - scroll_pixel_position.x,
 9183        );
 9184
 9185        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9186
 9187        // Fully visible if it can be displayed within the window (allow overlapping other
 9188        // panes). However, this is only allowed if the popover starts within text_bounds.
 9189        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9190            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9191
 9192        let mut origin = if can_position_to_the_right {
 9193            point(
 9194                x_after_longest,
 9195                text_bounds.origin.y
 9196                    + Pixels::from(
 9197                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9198                            - scroll_pixel_position.y,
 9199                    ),
 9200            )
 9201        } else {
 9202            let cursor_row = newest_selection_head.map(|head| head.row());
 9203            let above_edit = edit_start
 9204                .row()
 9205                .0
 9206                .checked_sub(line_count as u32)
 9207                .map(DisplayRow);
 9208            let below_edit = Some(edit_end.row() + 1);
 9209            let above_cursor =
 9210                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9211            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9212
 9213            // Place the edit popover adjacent to the edit if there is a location
 9214            // available that is onscreen and does not obscure the cursor. Otherwise,
 9215            // place it adjacent to the cursor.
 9216            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9217                .into_iter()
 9218                .flatten()
 9219                .find(|&start_row| {
 9220                    let end_row = start_row + line_count as u32;
 9221                    visible_row_range.contains(&start_row)
 9222                        && visible_row_range.contains(&end_row)
 9223                        && cursor_row
 9224                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9225                })?;
 9226
 9227            content_origin
 9228                + point(
 9229                    Pixels::from(-scroll_pixel_position.x),
 9230                    Pixels::from(
 9231                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9232                    ),
 9233                )
 9234        };
 9235
 9236        origin.x -= BORDER_WIDTH;
 9237
 9238        window.defer_draw(element, origin, 1);
 9239
 9240        // Do not return an element, since it will already be drawn due to defer_draw.
 9241        None
 9242    }
 9243
 9244    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9245        px(30.)
 9246    }
 9247
 9248    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9249        if self.read_only(cx) {
 9250            cx.theme().players().read_only()
 9251        } else {
 9252            self.style.as_ref().unwrap().local_player
 9253        }
 9254    }
 9255
 9256    fn render_edit_prediction_accept_keybind(
 9257        &self,
 9258        window: &mut Window,
 9259        cx: &App,
 9260    ) -> Option<AnyElement> {
 9261        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9262        let accept_keystroke = accept_binding.keystroke()?;
 9263
 9264        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9265
 9266        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9267            Color::Accent
 9268        } else {
 9269            Color::Muted
 9270        };
 9271
 9272        h_flex()
 9273            .px_0p5()
 9274            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9275            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9276            .text_size(TextSize::XSmall.rems(cx))
 9277            .child(h_flex().children(ui::render_modifiers(
 9278                accept_keystroke.modifiers(),
 9279                PlatformStyle::platform(),
 9280                Some(modifiers_color),
 9281                Some(IconSize::XSmall.rems().into()),
 9282                true,
 9283            )))
 9284            .when(is_platform_style_mac, |parent| {
 9285                parent.child(accept_keystroke.key().to_string())
 9286            })
 9287            .when(!is_platform_style_mac, |parent| {
 9288                parent.child(
 9289                    Key::new(
 9290                        util::capitalize(accept_keystroke.key()),
 9291                        Some(Color::Default),
 9292                    )
 9293                    .size(Some(IconSize::XSmall.rems().into())),
 9294                )
 9295            })
 9296            .into_any()
 9297            .into()
 9298    }
 9299
 9300    fn render_edit_prediction_line_popover(
 9301        &self,
 9302        label: impl Into<SharedString>,
 9303        icon: Option<IconName>,
 9304        window: &mut Window,
 9305        cx: &App,
 9306    ) -> Stateful<Div> {
 9307        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9308
 9309        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9310        let has_keybind = keybind.is_some();
 9311
 9312        h_flex()
 9313            .id("ep-line-popover")
 9314            .py_0p5()
 9315            .pl_1()
 9316            .pr(padding_right)
 9317            .gap_1()
 9318            .rounded_md()
 9319            .border_1()
 9320            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9321            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9322            .shadow_xs()
 9323            .when(!has_keybind, |el| {
 9324                let status_colors = cx.theme().status();
 9325
 9326                el.bg(status_colors.error_background)
 9327                    .border_color(status_colors.error.opacity(0.6))
 9328                    .pl_2()
 9329                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9330                    .cursor_default()
 9331                    .hoverable_tooltip(move |_window, cx| {
 9332                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9333                    })
 9334            })
 9335            .children(keybind)
 9336            .child(
 9337                Label::new(label)
 9338                    .size(LabelSize::Small)
 9339                    .when(!has_keybind, |el| {
 9340                        el.color(cx.theme().status().error.into()).strikethrough()
 9341                    }),
 9342            )
 9343            .when(!has_keybind, |el| {
 9344                el.child(
 9345                    h_flex().ml_1().child(
 9346                        Icon::new(IconName::Info)
 9347                            .size(IconSize::Small)
 9348                            .color(cx.theme().status().error.into()),
 9349                    ),
 9350                )
 9351            })
 9352            .when_some(icon, |element, icon| {
 9353                element.child(
 9354                    div()
 9355                        .mt(px(1.5))
 9356                        .child(Icon::new(icon).size(IconSize::Small)),
 9357                )
 9358            })
 9359    }
 9360
 9361    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9362        let accent_color = cx.theme().colors().text_accent;
 9363        let editor_bg_color = cx.theme().colors().editor_background;
 9364        editor_bg_color.blend(accent_color.opacity(0.1))
 9365    }
 9366
 9367    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9368        let accent_color = cx.theme().colors().text_accent;
 9369        let editor_bg_color = cx.theme().colors().editor_background;
 9370        editor_bg_color.blend(accent_color.opacity(0.6))
 9371    }
 9372    fn get_prediction_provider_icon_name(
 9373        provider: &Option<RegisteredEditPredictionProvider>,
 9374    ) -> IconName {
 9375        match provider {
 9376            Some(provider) => match provider.provider.name() {
 9377                "copilot" => IconName::Copilot,
 9378                "supermaven" => IconName::Supermaven,
 9379                _ => IconName::ZedPredict,
 9380            },
 9381            None => IconName::ZedPredict,
 9382        }
 9383    }
 9384
 9385    fn render_edit_prediction_cursor_popover(
 9386        &self,
 9387        min_width: Pixels,
 9388        max_width: Pixels,
 9389        cursor_point: Point,
 9390        style: &EditorStyle,
 9391        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9392        _window: &Window,
 9393        cx: &mut Context<Editor>,
 9394    ) -> Option<AnyElement> {
 9395        let provider = self.edit_prediction_provider.as_ref()?;
 9396        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9397
 9398        let is_refreshing = provider.provider.is_refreshing(cx);
 9399
 9400        fn pending_completion_container(icon: IconName) -> Div {
 9401            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9402        }
 9403
 9404        let completion = match &self.active_edit_prediction {
 9405            Some(prediction) => {
 9406                if !self.has_visible_completions_menu() {
 9407                    const RADIUS: Pixels = px(6.);
 9408                    const BORDER_WIDTH: Pixels = px(1.);
 9409
 9410                    return Some(
 9411                        h_flex()
 9412                            .elevation_2(cx)
 9413                            .border(BORDER_WIDTH)
 9414                            .border_color(cx.theme().colors().border)
 9415                            .when(accept_keystroke.is_none(), |el| {
 9416                                el.border_color(cx.theme().status().error)
 9417                            })
 9418                            .rounded(RADIUS)
 9419                            .rounded_tl(px(0.))
 9420                            .overflow_hidden()
 9421                            .child(div().px_1p5().child(match &prediction.completion {
 9422                                EditPrediction::MoveWithin { target, snapshot } => {
 9423                                    use text::ToPoint as _;
 9424                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9425                                    {
 9426                                        Icon::new(IconName::ZedPredictDown)
 9427                                    } else {
 9428                                        Icon::new(IconName::ZedPredictUp)
 9429                                    }
 9430                                }
 9431                                EditPrediction::MoveOutside { .. } => {
 9432                                    // TODO [zeta2] custom icon for external jump?
 9433                                    Icon::new(provider_icon)
 9434                                }
 9435                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9436                            }))
 9437                            .child(
 9438                                h_flex()
 9439                                    .gap_1()
 9440                                    .py_1()
 9441                                    .px_2()
 9442                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9443                                    .border_l_1()
 9444                                    .border_color(cx.theme().colors().border)
 9445                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9446                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9447                                        el.child(
 9448                                            Label::new("Hold")
 9449                                                .size(LabelSize::Small)
 9450                                                .when(accept_keystroke.is_none(), |el| {
 9451                                                    el.strikethrough()
 9452                                                })
 9453                                                .line_height_style(LineHeightStyle::UiLabel),
 9454                                        )
 9455                                    })
 9456                                    .id("edit_prediction_cursor_popover_keybind")
 9457                                    .when(accept_keystroke.is_none(), |el| {
 9458                                        let status_colors = cx.theme().status();
 9459
 9460                                        el.bg(status_colors.error_background)
 9461                                            .border_color(status_colors.error.opacity(0.6))
 9462                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9463                                            .cursor_default()
 9464                                            .hoverable_tooltip(move |_window, cx| {
 9465                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9466                                                    .into()
 9467                                            })
 9468                                    })
 9469                                    .when_some(
 9470                                        accept_keystroke.as_ref(),
 9471                                        |el, accept_keystroke| {
 9472                                            el.child(h_flex().children(ui::render_modifiers(
 9473                                                accept_keystroke.modifiers(),
 9474                                                PlatformStyle::platform(),
 9475                                                Some(Color::Default),
 9476                                                Some(IconSize::XSmall.rems().into()),
 9477                                                false,
 9478                                            )))
 9479                                        },
 9480                                    ),
 9481                            )
 9482                            .into_any(),
 9483                    );
 9484                }
 9485
 9486                self.render_edit_prediction_cursor_popover_preview(
 9487                    prediction,
 9488                    cursor_point,
 9489                    style,
 9490                    cx,
 9491                )?
 9492            }
 9493
 9494            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9495                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9496                    stale_completion,
 9497                    cursor_point,
 9498                    style,
 9499                    cx,
 9500                )?,
 9501
 9502                None => pending_completion_container(provider_icon)
 9503                    .child(Label::new("...").size(LabelSize::Small)),
 9504            },
 9505
 9506            None => pending_completion_container(provider_icon)
 9507                .child(Label::new("...").size(LabelSize::Small)),
 9508        };
 9509
 9510        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9511            completion
 9512                .with_animation(
 9513                    "loading-completion",
 9514                    Animation::new(Duration::from_secs(2))
 9515                        .repeat()
 9516                        .with_easing(pulsating_between(0.4, 0.8)),
 9517                    |label, delta| label.opacity(delta),
 9518                )
 9519                .into_any_element()
 9520        } else {
 9521            completion.into_any_element()
 9522        };
 9523
 9524        let has_completion = self.active_edit_prediction.is_some();
 9525
 9526        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9527        Some(
 9528            h_flex()
 9529                .min_w(min_width)
 9530                .max_w(max_width)
 9531                .flex_1()
 9532                .elevation_2(cx)
 9533                .border_color(cx.theme().colors().border)
 9534                .child(
 9535                    div()
 9536                        .flex_1()
 9537                        .py_1()
 9538                        .px_2()
 9539                        .overflow_hidden()
 9540                        .child(completion),
 9541                )
 9542                .when_some(accept_keystroke, |el, accept_keystroke| {
 9543                    if !accept_keystroke.modifiers().modified() {
 9544                        return el;
 9545                    }
 9546
 9547                    el.child(
 9548                        h_flex()
 9549                            .h_full()
 9550                            .border_l_1()
 9551                            .rounded_r_lg()
 9552                            .border_color(cx.theme().colors().border)
 9553                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9554                            .gap_1()
 9555                            .py_1()
 9556                            .px_2()
 9557                            .child(
 9558                                h_flex()
 9559                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9560                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9561                                    .child(h_flex().children(ui::render_modifiers(
 9562                                        accept_keystroke.modifiers(),
 9563                                        PlatformStyle::platform(),
 9564                                        Some(if !has_completion {
 9565                                            Color::Muted
 9566                                        } else {
 9567                                            Color::Default
 9568                                        }),
 9569                                        None,
 9570                                        false,
 9571                                    ))),
 9572                            )
 9573                            .child(Label::new("Preview").into_any_element())
 9574                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9575                    )
 9576                })
 9577                .into_any(),
 9578        )
 9579    }
 9580
 9581    fn render_edit_prediction_cursor_popover_preview(
 9582        &self,
 9583        completion: &EditPredictionState,
 9584        cursor_point: Point,
 9585        style: &EditorStyle,
 9586        cx: &mut Context<Editor>,
 9587    ) -> Option<Div> {
 9588        use text::ToPoint as _;
 9589
 9590        fn render_relative_row_jump(
 9591            prefix: impl Into<String>,
 9592            current_row: u32,
 9593            target_row: u32,
 9594        ) -> Div {
 9595            let (row_diff, arrow) = if target_row < current_row {
 9596                (current_row - target_row, IconName::ArrowUp)
 9597            } else {
 9598                (target_row - current_row, IconName::ArrowDown)
 9599            };
 9600
 9601            h_flex()
 9602                .child(
 9603                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9604                        .color(Color::Muted)
 9605                        .size(LabelSize::Small),
 9606                )
 9607                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9608        }
 9609
 9610        let supports_jump = self
 9611            .edit_prediction_provider
 9612            .as_ref()
 9613            .map(|provider| provider.provider.supports_jump_to_edit())
 9614            .unwrap_or(true);
 9615
 9616        match &completion.completion {
 9617            EditPrediction::MoveWithin {
 9618                target, snapshot, ..
 9619            } => {
 9620                if !supports_jump {
 9621                    return None;
 9622                }
 9623
 9624                Some(
 9625                    h_flex()
 9626                        .px_2()
 9627                        .gap_2()
 9628                        .flex_1()
 9629                        .child(
 9630                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9631                                Icon::new(IconName::ZedPredictDown)
 9632                            } else {
 9633                                Icon::new(IconName::ZedPredictUp)
 9634                            },
 9635                        )
 9636                        .child(Label::new("Jump to Edit")),
 9637                )
 9638            }
 9639            EditPrediction::MoveOutside { snapshot, .. } => {
 9640                let file_name = snapshot
 9641                    .file()
 9642                    .map(|file| file.file_name(cx))
 9643                    .unwrap_or("untitled");
 9644                Some(
 9645                    h_flex()
 9646                        .px_2()
 9647                        .gap_2()
 9648                        .flex_1()
 9649                        .child(Icon::new(IconName::ZedPredict))
 9650                        .child(Label::new(format!("Jump to {file_name}"))),
 9651                )
 9652            }
 9653            EditPrediction::Edit {
 9654                edits,
 9655                edit_preview,
 9656                snapshot,
 9657                display_mode: _,
 9658            } => {
 9659                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9660
 9661                let (highlighted_edits, has_more_lines) =
 9662                    if let Some(edit_preview) = edit_preview.as_ref() {
 9663                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9664                            .first_line_preview()
 9665                    } else {
 9666                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9667                    };
 9668
 9669                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9670                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9671
 9672                let preview = h_flex()
 9673                    .gap_1()
 9674                    .min_w_16()
 9675                    .child(styled_text)
 9676                    .when(has_more_lines, |parent| parent.child(""));
 9677
 9678                let left = if supports_jump && first_edit_row != cursor_point.row {
 9679                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9680                        .into_any_element()
 9681                } else {
 9682                    let icon_name =
 9683                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9684                    Icon::new(icon_name).into_any_element()
 9685                };
 9686
 9687                Some(
 9688                    h_flex()
 9689                        .h_full()
 9690                        .flex_1()
 9691                        .gap_2()
 9692                        .pr_1()
 9693                        .overflow_x_hidden()
 9694                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9695                        .child(left)
 9696                        .child(preview),
 9697                )
 9698            }
 9699        }
 9700    }
 9701
 9702    pub fn render_context_menu(
 9703        &self,
 9704        style: &EditorStyle,
 9705        max_height_in_lines: u32,
 9706        window: &mut Window,
 9707        cx: &mut Context<Editor>,
 9708    ) -> Option<AnyElement> {
 9709        let menu = self.context_menu.borrow();
 9710        let menu = menu.as_ref()?;
 9711        if !menu.visible() {
 9712            return None;
 9713        };
 9714        Some(menu.render(style, max_height_in_lines, window, cx))
 9715    }
 9716
 9717    fn render_context_menu_aside(
 9718        &mut self,
 9719        max_size: Size<Pixels>,
 9720        window: &mut Window,
 9721        cx: &mut Context<Editor>,
 9722    ) -> Option<AnyElement> {
 9723        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9724            if menu.visible() {
 9725                menu.render_aside(max_size, window, cx)
 9726            } else {
 9727                None
 9728            }
 9729        })
 9730    }
 9731
 9732    fn hide_context_menu(
 9733        &mut self,
 9734        window: &mut Window,
 9735        cx: &mut Context<Self>,
 9736    ) -> Option<CodeContextMenu> {
 9737        cx.notify();
 9738        self.completion_tasks.clear();
 9739        let context_menu = self.context_menu.borrow_mut().take();
 9740        self.stale_edit_prediction_in_menu.take();
 9741        self.update_visible_edit_prediction(window, cx);
 9742        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9743            && let Some(completion_provider) = &self.completion_provider
 9744        {
 9745            completion_provider.selection_changed(None, window, cx);
 9746        }
 9747        context_menu
 9748    }
 9749
 9750    fn show_snippet_choices(
 9751        &mut self,
 9752        choices: &Vec<String>,
 9753        selection: Range<Anchor>,
 9754        cx: &mut Context<Self>,
 9755    ) {
 9756        let Some((_, buffer, _)) = self
 9757            .buffer()
 9758            .read(cx)
 9759            .excerpt_containing(selection.start, cx)
 9760        else {
 9761            return;
 9762        };
 9763        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9764        else {
 9765            return;
 9766        };
 9767        if buffer != end_buffer {
 9768            log::error!("expected anchor range to have matching buffer IDs");
 9769            return;
 9770        }
 9771
 9772        let id = post_inc(&mut self.next_completion_id);
 9773        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9774        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9775            CompletionsMenu::new_snippet_choices(
 9776                id,
 9777                true,
 9778                choices,
 9779                selection,
 9780                buffer,
 9781                snippet_sort_order,
 9782            ),
 9783        ));
 9784    }
 9785
 9786    pub fn insert_snippet(
 9787        &mut self,
 9788        insertion_ranges: &[Range<usize>],
 9789        snippet: Snippet,
 9790        window: &mut Window,
 9791        cx: &mut Context<Self>,
 9792    ) -> Result<()> {
 9793        struct Tabstop<T> {
 9794            is_end_tabstop: bool,
 9795            ranges: Vec<Range<T>>,
 9796            choices: Option<Vec<String>>,
 9797        }
 9798
 9799        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9800            let snippet_text: Arc<str> = snippet.text.clone().into();
 9801            let edits = insertion_ranges
 9802                .iter()
 9803                .cloned()
 9804                .map(|range| (range, snippet_text.clone()));
 9805            let autoindent_mode = AutoindentMode::Block {
 9806                original_indent_columns: Vec::new(),
 9807            };
 9808            buffer.edit(edits, Some(autoindent_mode), cx);
 9809
 9810            let snapshot = &*buffer.read(cx);
 9811            let snippet = &snippet;
 9812            snippet
 9813                .tabstops
 9814                .iter()
 9815                .map(|tabstop| {
 9816                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9817                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9818                    });
 9819                    let mut tabstop_ranges = tabstop
 9820                        .ranges
 9821                        .iter()
 9822                        .flat_map(|tabstop_range| {
 9823                            let mut delta = 0_isize;
 9824                            insertion_ranges.iter().map(move |insertion_range| {
 9825                                let insertion_start = insertion_range.start as isize + delta;
 9826                                delta +=
 9827                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9828
 9829                                let start = ((insertion_start + tabstop_range.start) as usize)
 9830                                    .min(snapshot.len());
 9831                                let end = ((insertion_start + tabstop_range.end) as usize)
 9832                                    .min(snapshot.len());
 9833                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9834                            })
 9835                        })
 9836                        .collect::<Vec<_>>();
 9837                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9838
 9839                    Tabstop {
 9840                        is_end_tabstop,
 9841                        ranges: tabstop_ranges,
 9842                        choices: tabstop.choices.clone(),
 9843                    }
 9844                })
 9845                .collect::<Vec<_>>()
 9846        });
 9847        if let Some(tabstop) = tabstops.first() {
 9848            self.change_selections(Default::default(), window, cx, |s| {
 9849                // Reverse order so that the first range is the newest created selection.
 9850                // Completions will use it and autoscroll will prioritize it.
 9851                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9852            });
 9853
 9854            if let Some(choices) = &tabstop.choices
 9855                && let Some(selection) = tabstop.ranges.first()
 9856            {
 9857                self.show_snippet_choices(choices, selection.clone(), cx)
 9858            }
 9859
 9860            // If we're already at the last tabstop and it's at the end of the snippet,
 9861            // we're done, we don't need to keep the state around.
 9862            if !tabstop.is_end_tabstop {
 9863                let choices = tabstops
 9864                    .iter()
 9865                    .map(|tabstop| tabstop.choices.clone())
 9866                    .collect();
 9867
 9868                let ranges = tabstops
 9869                    .into_iter()
 9870                    .map(|tabstop| tabstop.ranges)
 9871                    .collect::<Vec<_>>();
 9872
 9873                self.snippet_stack.push(SnippetState {
 9874                    active_index: 0,
 9875                    ranges,
 9876                    choices,
 9877                });
 9878            }
 9879
 9880            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9881            if self.autoclose_regions.is_empty() {
 9882                let snapshot = self.buffer.read(cx).snapshot(cx);
 9883                let mut all_selections = self.selections.all::<Point>(cx);
 9884                for selection in &mut all_selections {
 9885                    let selection_head = selection.head();
 9886                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9887                        continue;
 9888                    };
 9889
 9890                    let mut bracket_pair = None;
 9891                    let max_lookup_length = scope
 9892                        .brackets()
 9893                        .map(|(pair, _)| {
 9894                            pair.start
 9895                                .as_str()
 9896                                .chars()
 9897                                .count()
 9898                                .max(pair.end.as_str().chars().count())
 9899                        })
 9900                        .max();
 9901                    if let Some(max_lookup_length) = max_lookup_length {
 9902                        let next_text = snapshot
 9903                            .chars_at(selection_head)
 9904                            .take(max_lookup_length)
 9905                            .collect::<String>();
 9906                        let prev_text = snapshot
 9907                            .reversed_chars_at(selection_head)
 9908                            .take(max_lookup_length)
 9909                            .collect::<String>();
 9910
 9911                        for (pair, enabled) in scope.brackets() {
 9912                            if enabled
 9913                                && pair.close
 9914                                && prev_text.starts_with(pair.start.as_str())
 9915                                && next_text.starts_with(pair.end.as_str())
 9916                            {
 9917                                bracket_pair = Some(pair.clone());
 9918                                break;
 9919                            }
 9920                        }
 9921                    }
 9922
 9923                    if let Some(pair) = bracket_pair {
 9924                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9925                        let autoclose_enabled =
 9926                            self.use_autoclose && snapshot_settings.use_autoclose;
 9927                        if autoclose_enabled {
 9928                            let start = snapshot.anchor_after(selection_head);
 9929                            let end = snapshot.anchor_after(selection_head);
 9930                            self.autoclose_regions.push(AutocloseRegion {
 9931                                selection_id: selection.id,
 9932                                range: start..end,
 9933                                pair,
 9934                            });
 9935                        }
 9936                    }
 9937                }
 9938            }
 9939        }
 9940        Ok(())
 9941    }
 9942
 9943    pub fn move_to_next_snippet_tabstop(
 9944        &mut self,
 9945        window: &mut Window,
 9946        cx: &mut Context<Self>,
 9947    ) -> bool {
 9948        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9949    }
 9950
 9951    pub fn move_to_prev_snippet_tabstop(
 9952        &mut self,
 9953        window: &mut Window,
 9954        cx: &mut Context<Self>,
 9955    ) -> bool {
 9956        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9957    }
 9958
 9959    pub fn move_to_snippet_tabstop(
 9960        &mut self,
 9961        bias: Bias,
 9962        window: &mut Window,
 9963        cx: &mut Context<Self>,
 9964    ) -> bool {
 9965        if let Some(mut snippet) = self.snippet_stack.pop() {
 9966            match bias {
 9967                Bias::Left => {
 9968                    if snippet.active_index > 0 {
 9969                        snippet.active_index -= 1;
 9970                    } else {
 9971                        self.snippet_stack.push(snippet);
 9972                        return false;
 9973                    }
 9974                }
 9975                Bias::Right => {
 9976                    if snippet.active_index + 1 < snippet.ranges.len() {
 9977                        snippet.active_index += 1;
 9978                    } else {
 9979                        self.snippet_stack.push(snippet);
 9980                        return false;
 9981                    }
 9982                }
 9983            }
 9984            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9985                self.change_selections(Default::default(), window, cx, |s| {
 9986                    // Reverse order so that the first range is the newest created selection.
 9987                    // Completions will use it and autoscroll will prioritize it.
 9988                    s.select_ranges(current_ranges.iter().rev().cloned())
 9989                });
 9990
 9991                if let Some(choices) = &snippet.choices[snippet.active_index]
 9992                    && let Some(selection) = current_ranges.first()
 9993                {
 9994                    self.show_snippet_choices(choices, selection.clone(), cx);
 9995                }
 9996
 9997                // If snippet state is not at the last tabstop, push it back on the stack
 9998                if snippet.active_index + 1 < snippet.ranges.len() {
 9999                    self.snippet_stack.push(snippet);
10000                }
10001                return true;
10002            }
10003        }
10004
10005        false
10006    }
10007
10008    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10009        self.transact(window, cx, |this, window, cx| {
10010            this.select_all(&SelectAll, window, cx);
10011            this.insert("", window, cx);
10012        });
10013    }
10014
10015    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10016        if self.read_only(cx) {
10017            return;
10018        }
10019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10020        self.transact(window, cx, |this, window, cx| {
10021            this.select_autoclose_pair(window, cx);
10022            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10023            if !this.linked_edit_ranges.is_empty() {
10024                let selections = this.selections.all::<MultiBufferPoint>(cx);
10025                let snapshot = this.buffer.read(cx).snapshot(cx);
10026
10027                for selection in selections.iter() {
10028                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10029                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10030                    if selection_start.buffer_id != selection_end.buffer_id {
10031                        continue;
10032                    }
10033                    if let Some(ranges) =
10034                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10035                    {
10036                        for (buffer, entries) in ranges {
10037                            linked_ranges.entry(buffer).or_default().extend(entries);
10038                        }
10039                    }
10040                }
10041            }
10042
10043            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10044            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10045            for selection in &mut selections {
10046                if selection.is_empty() {
10047                    let old_head = selection.head();
10048                    let mut new_head =
10049                        movement::left(&display_map, old_head.to_display_point(&display_map))
10050                            .to_point(&display_map);
10051                    if let Some((buffer, line_buffer_range)) = display_map
10052                        .buffer_snapshot()
10053                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10054                    {
10055                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10056                        let indent_len = match indent_size.kind {
10057                            IndentKind::Space => {
10058                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10059                            }
10060                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10061                        };
10062                        if old_head.column <= indent_size.len && old_head.column > 0 {
10063                            let indent_len = indent_len.get();
10064                            new_head = cmp::min(
10065                                new_head,
10066                                MultiBufferPoint::new(
10067                                    old_head.row,
10068                                    ((old_head.column - 1) / indent_len) * indent_len,
10069                                ),
10070                            );
10071                        }
10072                    }
10073
10074                    selection.set_head(new_head, SelectionGoal::None);
10075                }
10076            }
10077
10078            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10079            this.insert("", window, cx);
10080            let empty_str: Arc<str> = Arc::from("");
10081            for (buffer, edits) in linked_ranges {
10082                let snapshot = buffer.read(cx).snapshot();
10083                use text::ToPoint as TP;
10084
10085                let edits = edits
10086                    .into_iter()
10087                    .map(|range| {
10088                        let end_point = TP::to_point(&range.end, &snapshot);
10089                        let mut start_point = TP::to_point(&range.start, &snapshot);
10090
10091                        if end_point == start_point {
10092                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10093                                .saturating_sub(1);
10094                            start_point =
10095                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10096                        };
10097
10098                        (start_point..end_point, empty_str.clone())
10099                    })
10100                    .sorted_by_key(|(range, _)| range.start)
10101                    .collect::<Vec<_>>();
10102                buffer.update(cx, |this, cx| {
10103                    this.edit(edits, None, cx);
10104                })
10105            }
10106            this.refresh_edit_prediction(true, false, window, cx);
10107            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10108        });
10109    }
10110
10111    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10112        if self.read_only(cx) {
10113            return;
10114        }
10115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10116        self.transact(window, cx, |this, window, cx| {
10117            this.change_selections(Default::default(), window, cx, |s| {
10118                s.move_with(|map, selection| {
10119                    if selection.is_empty() {
10120                        let cursor = movement::right(map, selection.head());
10121                        selection.end = cursor;
10122                        selection.reversed = true;
10123                        selection.goal = SelectionGoal::None;
10124                    }
10125                })
10126            });
10127            this.insert("", window, cx);
10128            this.refresh_edit_prediction(true, false, window, cx);
10129        });
10130    }
10131
10132    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10133        if self.mode.is_single_line() {
10134            cx.propagate();
10135            return;
10136        }
10137
10138        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10139        if self.move_to_prev_snippet_tabstop(window, cx) {
10140            return;
10141        }
10142        self.outdent(&Outdent, window, cx);
10143    }
10144
10145    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10146        if self.mode.is_single_line() {
10147            cx.propagate();
10148            return;
10149        }
10150
10151        if self.move_to_next_snippet_tabstop(window, cx) {
10152            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10153            return;
10154        }
10155        if self.read_only(cx) {
10156            return;
10157        }
10158        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10159        let mut selections = self.selections.all_adjusted(cx);
10160        let buffer = self.buffer.read(cx);
10161        let snapshot = buffer.snapshot(cx);
10162        let rows_iter = selections.iter().map(|s| s.head().row);
10163        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10164
10165        let has_some_cursor_in_whitespace = selections
10166            .iter()
10167            .filter(|selection| selection.is_empty())
10168            .any(|selection| {
10169                let cursor = selection.head();
10170                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10171                cursor.column < current_indent.len
10172            });
10173
10174        let mut edits = Vec::new();
10175        let mut prev_edited_row = 0;
10176        let mut row_delta = 0;
10177        for selection in &mut selections {
10178            if selection.start.row != prev_edited_row {
10179                row_delta = 0;
10180            }
10181            prev_edited_row = selection.end.row;
10182
10183            // If the selection is non-empty, then increase the indentation of the selected lines.
10184            if !selection.is_empty() {
10185                row_delta =
10186                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10187                continue;
10188            }
10189
10190            let cursor = selection.head();
10191            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10192            if let Some(suggested_indent) =
10193                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10194            {
10195                // Don't do anything if already at suggested indent
10196                // and there is any other cursor which is not
10197                if has_some_cursor_in_whitespace
10198                    && cursor.column == current_indent.len
10199                    && current_indent.len == suggested_indent.len
10200                {
10201                    continue;
10202                }
10203
10204                // Adjust line and move cursor to suggested indent
10205                // if cursor is not at suggested indent
10206                if cursor.column < suggested_indent.len
10207                    && cursor.column <= current_indent.len
10208                    && current_indent.len <= suggested_indent.len
10209                {
10210                    selection.start = Point::new(cursor.row, suggested_indent.len);
10211                    selection.end = selection.start;
10212                    if row_delta == 0 {
10213                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10214                            cursor.row,
10215                            current_indent,
10216                            suggested_indent,
10217                        ));
10218                        row_delta = suggested_indent.len - current_indent.len;
10219                    }
10220                    continue;
10221                }
10222
10223                // If current indent is more than suggested indent
10224                // only move cursor to current indent and skip indent
10225                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10226                    selection.start = Point::new(cursor.row, current_indent.len);
10227                    selection.end = selection.start;
10228                    continue;
10229                }
10230            }
10231
10232            // Otherwise, insert a hard or soft tab.
10233            let settings = buffer.language_settings_at(cursor, cx);
10234            let tab_size = if settings.hard_tabs {
10235                IndentSize::tab()
10236            } else {
10237                let tab_size = settings.tab_size.get();
10238                let indent_remainder = snapshot
10239                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10240                    .flat_map(str::chars)
10241                    .fold(row_delta % tab_size, |counter: u32, c| {
10242                        if c == '\t' {
10243                            0
10244                        } else {
10245                            (counter + 1) % tab_size
10246                        }
10247                    });
10248
10249                let chars_to_next_tab_stop = tab_size - indent_remainder;
10250                IndentSize::spaces(chars_to_next_tab_stop)
10251            };
10252            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10253            selection.end = selection.start;
10254            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10255            row_delta += tab_size.len;
10256        }
10257
10258        self.transact(window, cx, |this, window, cx| {
10259            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10260            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10261            this.refresh_edit_prediction(true, false, window, cx);
10262        });
10263    }
10264
10265    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10266        if self.read_only(cx) {
10267            return;
10268        }
10269        if self.mode.is_single_line() {
10270            cx.propagate();
10271            return;
10272        }
10273
10274        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10275        let mut selections = self.selections.all::<Point>(cx);
10276        let mut prev_edited_row = 0;
10277        let mut row_delta = 0;
10278        let mut edits = Vec::new();
10279        let buffer = self.buffer.read(cx);
10280        let snapshot = buffer.snapshot(cx);
10281        for selection in &mut selections {
10282            if selection.start.row != prev_edited_row {
10283                row_delta = 0;
10284            }
10285            prev_edited_row = selection.end.row;
10286
10287            row_delta =
10288                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10289        }
10290
10291        self.transact(window, cx, |this, window, cx| {
10292            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10293            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10294        });
10295    }
10296
10297    fn indent_selection(
10298        buffer: &MultiBuffer,
10299        snapshot: &MultiBufferSnapshot,
10300        selection: &mut Selection<Point>,
10301        edits: &mut Vec<(Range<Point>, String)>,
10302        delta_for_start_row: u32,
10303        cx: &App,
10304    ) -> u32 {
10305        let settings = buffer.language_settings_at(selection.start, cx);
10306        let tab_size = settings.tab_size.get();
10307        let indent_kind = if settings.hard_tabs {
10308            IndentKind::Tab
10309        } else {
10310            IndentKind::Space
10311        };
10312        let mut start_row = selection.start.row;
10313        let mut end_row = selection.end.row + 1;
10314
10315        // If a selection ends at the beginning of a line, don't indent
10316        // that last line.
10317        if selection.end.column == 0 && selection.end.row > selection.start.row {
10318            end_row -= 1;
10319        }
10320
10321        // Avoid re-indenting a row that has already been indented by a
10322        // previous selection, but still update this selection's column
10323        // to reflect that indentation.
10324        if delta_for_start_row > 0 {
10325            start_row += 1;
10326            selection.start.column += delta_for_start_row;
10327            if selection.end.row == selection.start.row {
10328                selection.end.column += delta_for_start_row;
10329            }
10330        }
10331
10332        let mut delta_for_end_row = 0;
10333        let has_multiple_rows = start_row + 1 != end_row;
10334        for row in start_row..end_row {
10335            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10336            let indent_delta = match (current_indent.kind, indent_kind) {
10337                (IndentKind::Space, IndentKind::Space) => {
10338                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10339                    IndentSize::spaces(columns_to_next_tab_stop)
10340                }
10341                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10342                (_, IndentKind::Tab) => IndentSize::tab(),
10343            };
10344
10345            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10346                0
10347            } else {
10348                selection.start.column
10349            };
10350            let row_start = Point::new(row, start);
10351            edits.push((
10352                row_start..row_start,
10353                indent_delta.chars().collect::<String>(),
10354            ));
10355
10356            // Update this selection's endpoints to reflect the indentation.
10357            if row == selection.start.row {
10358                selection.start.column += indent_delta.len;
10359            }
10360            if row == selection.end.row {
10361                selection.end.column += indent_delta.len;
10362                delta_for_end_row = indent_delta.len;
10363            }
10364        }
10365
10366        if selection.start.row == selection.end.row {
10367            delta_for_start_row + delta_for_end_row
10368        } else {
10369            delta_for_end_row
10370        }
10371    }
10372
10373    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10374        if self.read_only(cx) {
10375            return;
10376        }
10377        if self.mode.is_single_line() {
10378            cx.propagate();
10379            return;
10380        }
10381
10382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10383        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10384        let selections = self.selections.all::<Point>(cx);
10385        let mut deletion_ranges = Vec::new();
10386        let mut last_outdent = None;
10387        {
10388            let buffer = self.buffer.read(cx);
10389            let snapshot = buffer.snapshot(cx);
10390            for selection in &selections {
10391                let settings = buffer.language_settings_at(selection.start, cx);
10392                let tab_size = settings.tab_size.get();
10393                let mut rows = selection.spanned_rows(false, &display_map);
10394
10395                // Avoid re-outdenting a row that has already been outdented by a
10396                // previous selection.
10397                if let Some(last_row) = last_outdent
10398                    && last_row == rows.start
10399                {
10400                    rows.start = rows.start.next_row();
10401                }
10402                let has_multiple_rows = rows.len() > 1;
10403                for row in rows.iter_rows() {
10404                    let indent_size = snapshot.indent_size_for_line(row);
10405                    if indent_size.len > 0 {
10406                        let deletion_len = match indent_size.kind {
10407                            IndentKind::Space => {
10408                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10409                                if columns_to_prev_tab_stop == 0 {
10410                                    tab_size
10411                                } else {
10412                                    columns_to_prev_tab_stop
10413                                }
10414                            }
10415                            IndentKind::Tab => 1,
10416                        };
10417                        let start = if has_multiple_rows
10418                            || deletion_len > selection.start.column
10419                            || indent_size.len < selection.start.column
10420                        {
10421                            0
10422                        } else {
10423                            selection.start.column - deletion_len
10424                        };
10425                        deletion_ranges.push(
10426                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10427                        );
10428                        last_outdent = Some(row);
10429                    }
10430                }
10431            }
10432        }
10433
10434        self.transact(window, cx, |this, window, cx| {
10435            this.buffer.update(cx, |buffer, cx| {
10436                let empty_str: Arc<str> = Arc::default();
10437                buffer.edit(
10438                    deletion_ranges
10439                        .into_iter()
10440                        .map(|range| (range, empty_str.clone())),
10441                    None,
10442                    cx,
10443                );
10444            });
10445            let selections = this.selections.all::<usize>(cx);
10446            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10447        });
10448    }
10449
10450    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10451        if self.read_only(cx) {
10452            return;
10453        }
10454        if self.mode.is_single_line() {
10455            cx.propagate();
10456            return;
10457        }
10458
10459        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10460        let selections = self
10461            .selections
10462            .all::<usize>(cx)
10463            .into_iter()
10464            .map(|s| s.range());
10465
10466        self.transact(window, cx, |this, window, cx| {
10467            this.buffer.update(cx, |buffer, cx| {
10468                buffer.autoindent_ranges(selections, cx);
10469            });
10470            let selections = this.selections.all::<usize>(cx);
10471            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10472        });
10473    }
10474
10475    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10477        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10478        let selections = self.selections.all::<Point>(cx);
10479
10480        let mut new_cursors = Vec::new();
10481        let mut edit_ranges = Vec::new();
10482        let mut selections = selections.iter().peekable();
10483        while let Some(selection) = selections.next() {
10484            let mut rows = selection.spanned_rows(false, &display_map);
10485
10486            // Accumulate contiguous regions of rows that we want to delete.
10487            while let Some(next_selection) = selections.peek() {
10488                let next_rows = next_selection.spanned_rows(false, &display_map);
10489                if next_rows.start <= rows.end {
10490                    rows.end = next_rows.end;
10491                    selections.next().unwrap();
10492                } else {
10493                    break;
10494                }
10495            }
10496
10497            let buffer = display_map.buffer_snapshot();
10498            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10499            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10500                // If there's a line after the range, delete the \n from the end of the row range
10501                (
10502                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10503                    rows.end,
10504                )
10505            } else {
10506                // If there isn't a line after the range, delete the \n from the line before the
10507                // start of the row range
10508                edit_start = edit_start.saturating_sub(1);
10509                (buffer.len(), rows.start.previous_row())
10510            };
10511
10512            let text_layout_details = self.text_layout_details(window);
10513            let x = display_map.x_for_display_point(
10514                selection.head().to_display_point(&display_map),
10515                &text_layout_details,
10516            );
10517            let row = Point::new(target_row.0, 0)
10518                .to_display_point(&display_map)
10519                .row();
10520            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10521
10522            new_cursors.push((
10523                selection.id,
10524                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10525                SelectionGoal::None,
10526            ));
10527            edit_ranges.push(edit_start..edit_end);
10528        }
10529
10530        self.transact(window, cx, |this, window, cx| {
10531            let buffer = this.buffer.update(cx, |buffer, cx| {
10532                let empty_str: Arc<str> = Arc::default();
10533                buffer.edit(
10534                    edit_ranges
10535                        .into_iter()
10536                        .map(|range| (range, empty_str.clone())),
10537                    None,
10538                    cx,
10539                );
10540                buffer.snapshot(cx)
10541            });
10542            let new_selections = new_cursors
10543                .into_iter()
10544                .map(|(id, cursor, goal)| {
10545                    let cursor = cursor.to_point(&buffer);
10546                    Selection {
10547                        id,
10548                        start: cursor,
10549                        end: cursor,
10550                        reversed: false,
10551                        goal,
10552                    }
10553                })
10554                .collect();
10555
10556            this.change_selections(Default::default(), window, cx, |s| {
10557                s.select(new_selections);
10558            });
10559        });
10560    }
10561
10562    pub fn join_lines_impl(
10563        &mut self,
10564        insert_whitespace: bool,
10565        window: &mut Window,
10566        cx: &mut Context<Self>,
10567    ) {
10568        if self.read_only(cx) {
10569            return;
10570        }
10571        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10572        for selection in self.selections.all::<Point>(cx) {
10573            let start = MultiBufferRow(selection.start.row);
10574            // Treat single line selections as if they include the next line. Otherwise this action
10575            // would do nothing for single line selections individual cursors.
10576            let end = if selection.start.row == selection.end.row {
10577                MultiBufferRow(selection.start.row + 1)
10578            } else {
10579                MultiBufferRow(selection.end.row)
10580            };
10581
10582            if let Some(last_row_range) = row_ranges.last_mut()
10583                && start <= last_row_range.end
10584            {
10585                last_row_range.end = end;
10586                continue;
10587            }
10588            row_ranges.push(start..end);
10589        }
10590
10591        let snapshot = self.buffer.read(cx).snapshot(cx);
10592        let mut cursor_positions = Vec::new();
10593        for row_range in &row_ranges {
10594            let anchor = snapshot.anchor_before(Point::new(
10595                row_range.end.previous_row().0,
10596                snapshot.line_len(row_range.end.previous_row()),
10597            ));
10598            cursor_positions.push(anchor..anchor);
10599        }
10600
10601        self.transact(window, cx, |this, window, cx| {
10602            for row_range in row_ranges.into_iter().rev() {
10603                for row in row_range.iter_rows().rev() {
10604                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10605                    let next_line_row = row.next_row();
10606                    let indent = snapshot.indent_size_for_line(next_line_row);
10607                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10608
10609                    let replace =
10610                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10611                            " "
10612                        } else {
10613                            ""
10614                        };
10615
10616                    this.buffer.update(cx, |buffer, cx| {
10617                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10618                    });
10619                }
10620            }
10621
10622            this.change_selections(Default::default(), window, cx, |s| {
10623                s.select_anchor_ranges(cursor_positions)
10624            });
10625        });
10626    }
10627
10628    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10630        self.join_lines_impl(true, window, cx);
10631    }
10632
10633    pub fn sort_lines_case_sensitive(
10634        &mut self,
10635        _: &SortLinesCaseSensitive,
10636        window: &mut Window,
10637        cx: &mut Context<Self>,
10638    ) {
10639        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10640    }
10641
10642    pub fn sort_lines_by_length(
10643        &mut self,
10644        _: &SortLinesByLength,
10645        window: &mut Window,
10646        cx: &mut Context<Self>,
10647    ) {
10648        self.manipulate_immutable_lines(window, cx, |lines| {
10649            lines.sort_by_key(|&line| line.chars().count())
10650        })
10651    }
10652
10653    pub fn sort_lines_case_insensitive(
10654        &mut self,
10655        _: &SortLinesCaseInsensitive,
10656        window: &mut Window,
10657        cx: &mut Context<Self>,
10658    ) {
10659        self.manipulate_immutable_lines(window, cx, |lines| {
10660            lines.sort_by_key(|line| line.to_lowercase())
10661        })
10662    }
10663
10664    pub fn unique_lines_case_insensitive(
10665        &mut self,
10666        _: &UniqueLinesCaseInsensitive,
10667        window: &mut Window,
10668        cx: &mut Context<Self>,
10669    ) {
10670        self.manipulate_immutable_lines(window, cx, |lines| {
10671            let mut seen = HashSet::default();
10672            lines.retain(|line| seen.insert(line.to_lowercase()));
10673        })
10674    }
10675
10676    pub fn unique_lines_case_sensitive(
10677        &mut self,
10678        _: &UniqueLinesCaseSensitive,
10679        window: &mut Window,
10680        cx: &mut Context<Self>,
10681    ) {
10682        self.manipulate_immutable_lines(window, cx, |lines| {
10683            let mut seen = HashSet::default();
10684            lines.retain(|line| seen.insert(*line));
10685        })
10686    }
10687
10688    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10689        let snapshot = self.buffer.read(cx).snapshot(cx);
10690        for selection in self.selections.disjoint_anchors_arc().iter() {
10691            if snapshot
10692                .language_at(selection.start)
10693                .and_then(|lang| lang.config().wrap_characters.as_ref())
10694                .is_some()
10695            {
10696                return true;
10697            }
10698        }
10699        false
10700    }
10701
10702    fn wrap_selections_in_tag(
10703        &mut self,
10704        _: &WrapSelectionsInTag,
10705        window: &mut Window,
10706        cx: &mut Context<Self>,
10707    ) {
10708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10709
10710        let snapshot = self.buffer.read(cx).snapshot(cx);
10711
10712        let mut edits = Vec::new();
10713        let mut boundaries = Vec::new();
10714
10715        for selection in self.selections.all::<Point>(cx).iter() {
10716            let Some(wrap_config) = snapshot
10717                .language_at(selection.start)
10718                .and_then(|lang| lang.config().wrap_characters.clone())
10719            else {
10720                continue;
10721            };
10722
10723            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10724            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10725
10726            let start_before = snapshot.anchor_before(selection.start);
10727            let end_after = snapshot.anchor_after(selection.end);
10728
10729            edits.push((start_before..start_before, open_tag));
10730            edits.push((end_after..end_after, close_tag));
10731
10732            boundaries.push((
10733                start_before,
10734                end_after,
10735                wrap_config.start_prefix.len(),
10736                wrap_config.end_suffix.len(),
10737            ));
10738        }
10739
10740        if edits.is_empty() {
10741            return;
10742        }
10743
10744        self.transact(window, cx, |this, window, cx| {
10745            let buffer = this.buffer.update(cx, |buffer, cx| {
10746                buffer.edit(edits, None, cx);
10747                buffer.snapshot(cx)
10748            });
10749
10750            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10751            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10752                boundaries.into_iter()
10753            {
10754                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10755                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10756                new_selections.push(open_offset..open_offset);
10757                new_selections.push(close_offset..close_offset);
10758            }
10759
10760            this.change_selections(Default::default(), window, cx, |s| {
10761                s.select_ranges(new_selections);
10762            });
10763
10764            this.request_autoscroll(Autoscroll::fit(), cx);
10765        });
10766    }
10767
10768    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10769        let Some(project) = self.project.clone() else {
10770            return;
10771        };
10772        self.reload(project, window, cx)
10773            .detach_and_notify_err(window, cx);
10774    }
10775
10776    pub fn restore_file(
10777        &mut self,
10778        _: &::git::RestoreFile,
10779        window: &mut Window,
10780        cx: &mut Context<Self>,
10781    ) {
10782        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10783        let mut buffer_ids = HashSet::default();
10784        let snapshot = self.buffer().read(cx).snapshot(cx);
10785        for selection in self.selections.all::<usize>(cx) {
10786            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10787        }
10788
10789        let buffer = self.buffer().read(cx);
10790        let ranges = buffer_ids
10791            .into_iter()
10792            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10793            .collect::<Vec<_>>();
10794
10795        self.restore_hunks_in_ranges(ranges, window, cx);
10796    }
10797
10798    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10799        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10800        let selections = self
10801            .selections
10802            .all(cx)
10803            .into_iter()
10804            .map(|s| s.range())
10805            .collect();
10806        self.restore_hunks_in_ranges(selections, window, cx);
10807    }
10808
10809    pub fn restore_hunks_in_ranges(
10810        &mut self,
10811        ranges: Vec<Range<Point>>,
10812        window: &mut Window,
10813        cx: &mut Context<Editor>,
10814    ) {
10815        let mut revert_changes = HashMap::default();
10816        let chunk_by = self
10817            .snapshot(window, cx)
10818            .hunks_for_ranges(ranges)
10819            .into_iter()
10820            .chunk_by(|hunk| hunk.buffer_id);
10821        for (buffer_id, hunks) in &chunk_by {
10822            let hunks = hunks.collect::<Vec<_>>();
10823            for hunk in &hunks {
10824                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10825            }
10826            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10827        }
10828        drop(chunk_by);
10829        if !revert_changes.is_empty() {
10830            self.transact(window, cx, |editor, window, cx| {
10831                editor.restore(revert_changes, window, cx);
10832            });
10833        }
10834    }
10835
10836    pub fn open_active_item_in_terminal(
10837        &mut self,
10838        _: &OpenInTerminal,
10839        window: &mut Window,
10840        cx: &mut Context<Self>,
10841    ) {
10842        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10843            let project_path = buffer.read(cx).project_path(cx)?;
10844            let project = self.project()?.read(cx);
10845            let entry = project.entry_for_path(&project_path, cx)?;
10846            let parent = match &entry.canonical_path {
10847                Some(canonical_path) => canonical_path.to_path_buf(),
10848                None => project.absolute_path(&project_path, cx)?,
10849            }
10850            .parent()?
10851            .to_path_buf();
10852            Some(parent)
10853        }) {
10854            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10855        }
10856    }
10857
10858    fn set_breakpoint_context_menu(
10859        &mut self,
10860        display_row: DisplayRow,
10861        position: Option<Anchor>,
10862        clicked_point: gpui::Point<Pixels>,
10863        window: &mut Window,
10864        cx: &mut Context<Self>,
10865    ) {
10866        let source = self
10867            .buffer
10868            .read(cx)
10869            .snapshot(cx)
10870            .anchor_before(Point::new(display_row.0, 0u32));
10871
10872        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10873
10874        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10875            self,
10876            source,
10877            clicked_point,
10878            context_menu,
10879            window,
10880            cx,
10881        );
10882    }
10883
10884    fn add_edit_breakpoint_block(
10885        &mut self,
10886        anchor: Anchor,
10887        breakpoint: &Breakpoint,
10888        edit_action: BreakpointPromptEditAction,
10889        window: &mut Window,
10890        cx: &mut Context<Self>,
10891    ) {
10892        let weak_editor = cx.weak_entity();
10893        let bp_prompt = cx.new(|cx| {
10894            BreakpointPromptEditor::new(
10895                weak_editor,
10896                anchor,
10897                breakpoint.clone(),
10898                edit_action,
10899                window,
10900                cx,
10901            )
10902        });
10903
10904        let height = bp_prompt.update(cx, |this, cx| {
10905            this.prompt
10906                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10907        });
10908        let cloned_prompt = bp_prompt.clone();
10909        let blocks = vec![BlockProperties {
10910            style: BlockStyle::Sticky,
10911            placement: BlockPlacement::Above(anchor),
10912            height: Some(height),
10913            render: Arc::new(move |cx| {
10914                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10915                cloned_prompt.clone().into_any_element()
10916            }),
10917            priority: 0,
10918        }];
10919
10920        let focus_handle = bp_prompt.focus_handle(cx);
10921        window.focus(&focus_handle);
10922
10923        let block_ids = self.insert_blocks(blocks, None, cx);
10924        bp_prompt.update(cx, |prompt, _| {
10925            prompt.add_block_ids(block_ids);
10926        });
10927    }
10928
10929    pub(crate) fn breakpoint_at_row(
10930        &self,
10931        row: u32,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934    ) -> Option<(Anchor, Breakpoint)> {
10935        let snapshot = self.snapshot(window, cx);
10936        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10937
10938        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10939    }
10940
10941    pub(crate) fn breakpoint_at_anchor(
10942        &self,
10943        breakpoint_position: Anchor,
10944        snapshot: &EditorSnapshot,
10945        cx: &mut Context<Self>,
10946    ) -> Option<(Anchor, Breakpoint)> {
10947        let buffer = self
10948            .buffer
10949            .read(cx)
10950            .buffer_for_anchor(breakpoint_position, cx)?;
10951
10952        let enclosing_excerpt = breakpoint_position.excerpt_id;
10953        let buffer_snapshot = buffer.read(cx).snapshot();
10954
10955        let row = buffer_snapshot
10956            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10957            .row;
10958
10959        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10960        let anchor_end = snapshot
10961            .buffer_snapshot()
10962            .anchor_after(Point::new(row, line_len));
10963
10964        self.breakpoint_store
10965            .as_ref()?
10966            .read_with(cx, |breakpoint_store, cx| {
10967                breakpoint_store
10968                    .breakpoints(
10969                        &buffer,
10970                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10971                        &buffer_snapshot,
10972                        cx,
10973                    )
10974                    .next()
10975                    .and_then(|(bp, _)| {
10976                        let breakpoint_row = buffer_snapshot
10977                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10978                            .row;
10979
10980                        if breakpoint_row == row {
10981                            snapshot
10982                                .buffer_snapshot()
10983                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10984                                .map(|position| (position, bp.bp.clone()))
10985                        } else {
10986                            None
10987                        }
10988                    })
10989            })
10990    }
10991
10992    pub fn edit_log_breakpoint(
10993        &mut self,
10994        _: &EditLogBreakpoint,
10995        window: &mut Window,
10996        cx: &mut Context<Self>,
10997    ) {
10998        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10999            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11000                message: None,
11001                state: BreakpointState::Enabled,
11002                condition: None,
11003                hit_condition: None,
11004            });
11005
11006            self.add_edit_breakpoint_block(
11007                anchor,
11008                &breakpoint,
11009                BreakpointPromptEditAction::Log,
11010                window,
11011                cx,
11012            );
11013        }
11014    }
11015
11016    fn breakpoints_at_cursors(
11017        &self,
11018        window: &mut Window,
11019        cx: &mut Context<Self>,
11020    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11021        let snapshot = self.snapshot(window, cx);
11022        let cursors = self
11023            .selections
11024            .disjoint_anchors_arc()
11025            .iter()
11026            .map(|selection| {
11027                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11028
11029                let breakpoint_position = self
11030                    .breakpoint_at_row(cursor_position.row, window, cx)
11031                    .map(|bp| bp.0)
11032                    .unwrap_or_else(|| {
11033                        snapshot
11034                            .display_snapshot
11035                            .buffer_snapshot()
11036                            .anchor_after(Point::new(cursor_position.row, 0))
11037                    });
11038
11039                let breakpoint = self
11040                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11041                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11042
11043                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11044            })
11045            // 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.
11046            .collect::<HashMap<Anchor, _>>();
11047
11048        cursors.into_iter().collect()
11049    }
11050
11051    pub fn enable_breakpoint(
11052        &mut self,
11053        _: &crate::actions::EnableBreakpoint,
11054        window: &mut Window,
11055        cx: &mut Context<Self>,
11056    ) {
11057        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11058            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11059                continue;
11060            };
11061            self.edit_breakpoint_at_anchor(
11062                anchor,
11063                breakpoint,
11064                BreakpointEditAction::InvertState,
11065                cx,
11066            );
11067        }
11068    }
11069
11070    pub fn disable_breakpoint(
11071        &mut self,
11072        _: &crate::actions::DisableBreakpoint,
11073        window: &mut Window,
11074        cx: &mut Context<Self>,
11075    ) {
11076        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11077            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11078                continue;
11079            };
11080            self.edit_breakpoint_at_anchor(
11081                anchor,
11082                breakpoint,
11083                BreakpointEditAction::InvertState,
11084                cx,
11085            );
11086        }
11087    }
11088
11089    pub fn toggle_breakpoint(
11090        &mut self,
11091        _: &crate::actions::ToggleBreakpoint,
11092        window: &mut Window,
11093        cx: &mut Context<Self>,
11094    ) {
11095        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11096            if let Some(breakpoint) = breakpoint {
11097                self.edit_breakpoint_at_anchor(
11098                    anchor,
11099                    breakpoint,
11100                    BreakpointEditAction::Toggle,
11101                    cx,
11102                );
11103            } else {
11104                self.edit_breakpoint_at_anchor(
11105                    anchor,
11106                    Breakpoint::new_standard(),
11107                    BreakpointEditAction::Toggle,
11108                    cx,
11109                );
11110            }
11111        }
11112    }
11113
11114    pub fn edit_breakpoint_at_anchor(
11115        &mut self,
11116        breakpoint_position: Anchor,
11117        breakpoint: Breakpoint,
11118        edit_action: BreakpointEditAction,
11119        cx: &mut Context<Self>,
11120    ) {
11121        let Some(breakpoint_store) = &self.breakpoint_store else {
11122            return;
11123        };
11124
11125        let Some(buffer) = self
11126            .buffer
11127            .read(cx)
11128            .buffer_for_anchor(breakpoint_position, cx)
11129        else {
11130            return;
11131        };
11132
11133        breakpoint_store.update(cx, |breakpoint_store, cx| {
11134            breakpoint_store.toggle_breakpoint(
11135                buffer,
11136                BreakpointWithPosition {
11137                    position: breakpoint_position.text_anchor,
11138                    bp: breakpoint,
11139                },
11140                edit_action,
11141                cx,
11142            );
11143        });
11144
11145        cx.notify();
11146    }
11147
11148    #[cfg(any(test, feature = "test-support"))]
11149    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11150        self.breakpoint_store.clone()
11151    }
11152
11153    pub fn prepare_restore_change(
11154        &self,
11155        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11156        hunk: &MultiBufferDiffHunk,
11157        cx: &mut App,
11158    ) -> Option<()> {
11159        if hunk.is_created_file() {
11160            return None;
11161        }
11162        let buffer = self.buffer.read(cx);
11163        let diff = buffer.diff_for(hunk.buffer_id)?;
11164        let buffer = buffer.buffer(hunk.buffer_id)?;
11165        let buffer = buffer.read(cx);
11166        let original_text = diff
11167            .read(cx)
11168            .base_text()
11169            .as_rope()
11170            .slice(hunk.diff_base_byte_range.clone());
11171        let buffer_snapshot = buffer.snapshot();
11172        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11173        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11174            probe
11175                .0
11176                .start
11177                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11178                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11179        }) {
11180            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11181            Some(())
11182        } else {
11183            None
11184        }
11185    }
11186
11187    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11188        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11189    }
11190
11191    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11192        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11193    }
11194
11195    fn manipulate_lines<M>(
11196        &mut self,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199        mut manipulate: M,
11200    ) where
11201        M: FnMut(&str) -> LineManipulationResult,
11202    {
11203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11204
11205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11206        let buffer = self.buffer.read(cx).snapshot(cx);
11207
11208        let mut edits = Vec::new();
11209
11210        let selections = self.selections.all::<Point>(cx);
11211        let mut selections = selections.iter().peekable();
11212        let mut contiguous_row_selections = Vec::new();
11213        let mut new_selections = Vec::new();
11214        let mut added_lines = 0;
11215        let mut removed_lines = 0;
11216
11217        while let Some(selection) = selections.next() {
11218            let (start_row, end_row) = consume_contiguous_rows(
11219                &mut contiguous_row_selections,
11220                selection,
11221                &display_map,
11222                &mut selections,
11223            );
11224
11225            let start_point = Point::new(start_row.0, 0);
11226            let end_point = Point::new(
11227                end_row.previous_row().0,
11228                buffer.line_len(end_row.previous_row()),
11229            );
11230            let text = buffer
11231                .text_for_range(start_point..end_point)
11232                .collect::<String>();
11233
11234            let LineManipulationResult {
11235                new_text,
11236                line_count_before,
11237                line_count_after,
11238            } = manipulate(&text);
11239
11240            edits.push((start_point..end_point, new_text));
11241
11242            // Selections must change based on added and removed line count
11243            let start_row =
11244                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11245            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11246            new_selections.push(Selection {
11247                id: selection.id,
11248                start: start_row,
11249                end: end_row,
11250                goal: SelectionGoal::None,
11251                reversed: selection.reversed,
11252            });
11253
11254            if line_count_after > line_count_before {
11255                added_lines += line_count_after - line_count_before;
11256            } else if line_count_before > line_count_after {
11257                removed_lines += line_count_before - line_count_after;
11258            }
11259        }
11260
11261        self.transact(window, cx, |this, window, cx| {
11262            let buffer = this.buffer.update(cx, |buffer, cx| {
11263                buffer.edit(edits, None, cx);
11264                buffer.snapshot(cx)
11265            });
11266
11267            // Recalculate offsets on newly edited buffer
11268            let new_selections = new_selections
11269                .iter()
11270                .map(|s| {
11271                    let start_point = Point::new(s.start.0, 0);
11272                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11273                    Selection {
11274                        id: s.id,
11275                        start: buffer.point_to_offset(start_point),
11276                        end: buffer.point_to_offset(end_point),
11277                        goal: s.goal,
11278                        reversed: s.reversed,
11279                    }
11280                })
11281                .collect();
11282
11283            this.change_selections(Default::default(), window, cx, |s| {
11284                s.select(new_selections);
11285            });
11286
11287            this.request_autoscroll(Autoscroll::fit(), cx);
11288        });
11289    }
11290
11291    fn manipulate_immutable_lines<Fn>(
11292        &mut self,
11293        window: &mut Window,
11294        cx: &mut Context<Self>,
11295        mut callback: Fn,
11296    ) where
11297        Fn: FnMut(&mut Vec<&str>),
11298    {
11299        self.manipulate_lines(window, cx, |text| {
11300            let mut lines: Vec<&str> = text.split('\n').collect();
11301            let line_count_before = lines.len();
11302
11303            callback(&mut lines);
11304
11305            LineManipulationResult {
11306                new_text: lines.join("\n"),
11307                line_count_before,
11308                line_count_after: lines.len(),
11309            }
11310        });
11311    }
11312
11313    fn manipulate_mutable_lines<Fn>(
11314        &mut self,
11315        window: &mut Window,
11316        cx: &mut Context<Self>,
11317        mut callback: Fn,
11318    ) where
11319        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11320    {
11321        self.manipulate_lines(window, cx, |text| {
11322            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11323            let line_count_before = lines.len();
11324
11325            callback(&mut lines);
11326
11327            LineManipulationResult {
11328                new_text: lines.join("\n"),
11329                line_count_before,
11330                line_count_after: lines.len(),
11331            }
11332        });
11333    }
11334
11335    pub fn convert_indentation_to_spaces(
11336        &mut self,
11337        _: &ConvertIndentationToSpaces,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        let settings = self.buffer.read(cx).language_settings(cx);
11342        let tab_size = settings.tab_size.get() as usize;
11343
11344        self.manipulate_mutable_lines(window, cx, |lines| {
11345            // Allocates a reasonably sized scratch buffer once for the whole loop
11346            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11347            // Avoids recomputing spaces that could be inserted many times
11348            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11349                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11350                .collect();
11351
11352            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11353                let mut chars = line.as_ref().chars();
11354                let mut col = 0;
11355                let mut changed = false;
11356
11357                for ch in chars.by_ref() {
11358                    match ch {
11359                        ' ' => {
11360                            reindented_line.push(' ');
11361                            col += 1;
11362                        }
11363                        '\t' => {
11364                            // \t are converted to spaces depending on the current column
11365                            let spaces_len = tab_size - (col % tab_size);
11366                            reindented_line.extend(&space_cache[spaces_len - 1]);
11367                            col += spaces_len;
11368                            changed = true;
11369                        }
11370                        _ => {
11371                            // If we dont append before break, the character is consumed
11372                            reindented_line.push(ch);
11373                            break;
11374                        }
11375                    }
11376                }
11377
11378                if !changed {
11379                    reindented_line.clear();
11380                    continue;
11381                }
11382                // Append the rest of the line and replace old reference with new one
11383                reindented_line.extend(chars);
11384                *line = Cow::Owned(reindented_line.clone());
11385                reindented_line.clear();
11386            }
11387        });
11388    }
11389
11390    pub fn convert_indentation_to_tabs(
11391        &mut self,
11392        _: &ConvertIndentationToTabs,
11393        window: &mut Window,
11394        cx: &mut Context<Self>,
11395    ) {
11396        let settings = self.buffer.read(cx).language_settings(cx);
11397        let tab_size = settings.tab_size.get() as usize;
11398
11399        self.manipulate_mutable_lines(window, cx, |lines| {
11400            // Allocates a reasonably sized buffer once for the whole loop
11401            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11402            // Avoids recomputing spaces that could be inserted many times
11403            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11404                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11405                .collect();
11406
11407            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11408                let mut chars = line.chars();
11409                let mut spaces_count = 0;
11410                let mut first_non_indent_char = None;
11411                let mut changed = false;
11412
11413                for ch in chars.by_ref() {
11414                    match ch {
11415                        ' ' => {
11416                            // Keep track of spaces. Append \t when we reach tab_size
11417                            spaces_count += 1;
11418                            changed = true;
11419                            if spaces_count == tab_size {
11420                                reindented_line.push('\t');
11421                                spaces_count = 0;
11422                            }
11423                        }
11424                        '\t' => {
11425                            reindented_line.push('\t');
11426                            spaces_count = 0;
11427                        }
11428                        _ => {
11429                            // Dont append it yet, we might have remaining spaces
11430                            first_non_indent_char = Some(ch);
11431                            break;
11432                        }
11433                    }
11434                }
11435
11436                if !changed {
11437                    reindented_line.clear();
11438                    continue;
11439                }
11440                // Remaining spaces that didn't make a full tab stop
11441                if spaces_count > 0 {
11442                    reindented_line.extend(&space_cache[spaces_count - 1]);
11443                }
11444                // If we consume an extra character that was not indentation, add it back
11445                if let Some(extra_char) = first_non_indent_char {
11446                    reindented_line.push(extra_char);
11447                }
11448                // Append the rest of the line and replace old reference with new one
11449                reindented_line.extend(chars);
11450                *line = Cow::Owned(reindented_line.clone());
11451                reindented_line.clear();
11452            }
11453        });
11454    }
11455
11456    pub fn convert_to_upper_case(
11457        &mut self,
11458        _: &ConvertToUpperCase,
11459        window: &mut Window,
11460        cx: &mut Context<Self>,
11461    ) {
11462        self.manipulate_text(window, cx, |text| text.to_uppercase())
11463    }
11464
11465    pub fn convert_to_lower_case(
11466        &mut self,
11467        _: &ConvertToLowerCase,
11468        window: &mut Window,
11469        cx: &mut Context<Self>,
11470    ) {
11471        self.manipulate_text(window, cx, |text| text.to_lowercase())
11472    }
11473
11474    pub fn convert_to_title_case(
11475        &mut self,
11476        _: &ConvertToTitleCase,
11477        window: &mut Window,
11478        cx: &mut Context<Self>,
11479    ) {
11480        self.manipulate_text(window, cx, |text| {
11481            text.split('\n')
11482                .map(|line| line.to_case(Case::Title))
11483                .join("\n")
11484        })
11485    }
11486
11487    pub fn convert_to_snake_case(
11488        &mut self,
11489        _: &ConvertToSnakeCase,
11490        window: &mut Window,
11491        cx: &mut Context<Self>,
11492    ) {
11493        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11494    }
11495
11496    pub fn convert_to_kebab_case(
11497        &mut self,
11498        _: &ConvertToKebabCase,
11499        window: &mut Window,
11500        cx: &mut Context<Self>,
11501    ) {
11502        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11503    }
11504
11505    pub fn convert_to_upper_camel_case(
11506        &mut self,
11507        _: &ConvertToUpperCamelCase,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        self.manipulate_text(window, cx, |text| {
11512            text.split('\n')
11513                .map(|line| line.to_case(Case::UpperCamel))
11514                .join("\n")
11515        })
11516    }
11517
11518    pub fn convert_to_lower_camel_case(
11519        &mut self,
11520        _: &ConvertToLowerCamelCase,
11521        window: &mut Window,
11522        cx: &mut Context<Self>,
11523    ) {
11524        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11525    }
11526
11527    pub fn convert_to_opposite_case(
11528        &mut self,
11529        _: &ConvertToOppositeCase,
11530        window: &mut Window,
11531        cx: &mut Context<Self>,
11532    ) {
11533        self.manipulate_text(window, cx, |text| {
11534            text.chars()
11535                .fold(String::with_capacity(text.len()), |mut t, c| {
11536                    if c.is_uppercase() {
11537                        t.extend(c.to_lowercase());
11538                    } else {
11539                        t.extend(c.to_uppercase());
11540                    }
11541                    t
11542                })
11543        })
11544    }
11545
11546    pub fn convert_to_sentence_case(
11547        &mut self,
11548        _: &ConvertToSentenceCase,
11549        window: &mut Window,
11550        cx: &mut Context<Self>,
11551    ) {
11552        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11553    }
11554
11555    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11556        self.manipulate_text(window, cx, |text| {
11557            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11558            if has_upper_case_characters {
11559                text.to_lowercase()
11560            } else {
11561                text.to_uppercase()
11562            }
11563        })
11564    }
11565
11566    pub fn convert_to_rot13(
11567        &mut self,
11568        _: &ConvertToRot13,
11569        window: &mut Window,
11570        cx: &mut Context<Self>,
11571    ) {
11572        self.manipulate_text(window, cx, |text| {
11573            text.chars()
11574                .map(|c| match c {
11575                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11576                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11577                    _ => c,
11578                })
11579                .collect()
11580        })
11581    }
11582
11583    pub fn convert_to_rot47(
11584        &mut self,
11585        _: &ConvertToRot47,
11586        window: &mut Window,
11587        cx: &mut Context<Self>,
11588    ) {
11589        self.manipulate_text(window, cx, |text| {
11590            text.chars()
11591                .map(|c| {
11592                    let code_point = c as u32;
11593                    if code_point >= 33 && code_point <= 126 {
11594                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11595                    }
11596                    c
11597                })
11598                .collect()
11599        })
11600    }
11601
11602    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11603    where
11604        Fn: FnMut(&str) -> String,
11605    {
11606        let buffer = self.buffer.read(cx).snapshot(cx);
11607
11608        let mut new_selections = Vec::new();
11609        let mut edits = Vec::new();
11610        let mut selection_adjustment = 0i32;
11611
11612        for selection in self.selections.all_adjusted(cx) {
11613            let selection_is_empty = selection.is_empty();
11614
11615            let (start, end) = if selection_is_empty {
11616                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11617                (word_range.start, word_range.end)
11618            } else {
11619                (
11620                    buffer.point_to_offset(selection.start),
11621                    buffer.point_to_offset(selection.end),
11622                )
11623            };
11624
11625            let text = buffer.text_for_range(start..end).collect::<String>();
11626            let old_length = text.len() as i32;
11627            let text = callback(&text);
11628
11629            new_selections.push(Selection {
11630                start: (start as i32 - selection_adjustment) as usize,
11631                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11632                goal: SelectionGoal::None,
11633                id: selection.id,
11634                reversed: selection.reversed,
11635            });
11636
11637            selection_adjustment += old_length - text.len() as i32;
11638
11639            edits.push((start..end, text));
11640        }
11641
11642        self.transact(window, cx, |this, window, cx| {
11643            this.buffer.update(cx, |buffer, cx| {
11644                buffer.edit(edits, None, cx);
11645            });
11646
11647            this.change_selections(Default::default(), window, cx, |s| {
11648                s.select(new_selections);
11649            });
11650
11651            this.request_autoscroll(Autoscroll::fit(), cx);
11652        });
11653    }
11654
11655    pub fn move_selection_on_drop(
11656        &mut self,
11657        selection: &Selection<Anchor>,
11658        target: DisplayPoint,
11659        is_cut: bool,
11660        window: &mut Window,
11661        cx: &mut Context<Self>,
11662    ) {
11663        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11664        let buffer = display_map.buffer_snapshot();
11665        let mut edits = Vec::new();
11666        let insert_point = display_map
11667            .clip_point(target, Bias::Left)
11668            .to_point(&display_map);
11669        let text = buffer
11670            .text_for_range(selection.start..selection.end)
11671            .collect::<String>();
11672        if is_cut {
11673            edits.push(((selection.start..selection.end), String::new()));
11674        }
11675        let insert_anchor = buffer.anchor_before(insert_point);
11676        edits.push(((insert_anchor..insert_anchor), text));
11677        let last_edit_start = insert_anchor.bias_left(buffer);
11678        let last_edit_end = insert_anchor.bias_right(buffer);
11679        self.transact(window, cx, |this, window, cx| {
11680            this.buffer.update(cx, |buffer, cx| {
11681                buffer.edit(edits, None, cx);
11682            });
11683            this.change_selections(Default::default(), window, cx, |s| {
11684                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11685            });
11686        });
11687    }
11688
11689    pub fn clear_selection_drag_state(&mut self) {
11690        self.selection_drag_state = SelectionDragState::None;
11691    }
11692
11693    pub fn duplicate(
11694        &mut self,
11695        upwards: bool,
11696        whole_lines: bool,
11697        window: &mut Window,
11698        cx: &mut Context<Self>,
11699    ) {
11700        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11701
11702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11703        let buffer = display_map.buffer_snapshot();
11704        let selections = self.selections.all::<Point>(cx);
11705
11706        let mut edits = Vec::new();
11707        let mut selections_iter = selections.iter().peekable();
11708        while let Some(selection) = selections_iter.next() {
11709            let mut rows = selection.spanned_rows(false, &display_map);
11710            // duplicate line-wise
11711            if whole_lines || selection.start == selection.end {
11712                // Avoid duplicating the same lines twice.
11713                while let Some(next_selection) = selections_iter.peek() {
11714                    let next_rows = next_selection.spanned_rows(false, &display_map);
11715                    if next_rows.start < rows.end {
11716                        rows.end = next_rows.end;
11717                        selections_iter.next().unwrap();
11718                    } else {
11719                        break;
11720                    }
11721                }
11722
11723                // Copy the text from the selected row region and splice it either at the start
11724                // or end of the region.
11725                let start = Point::new(rows.start.0, 0);
11726                let end = Point::new(
11727                    rows.end.previous_row().0,
11728                    buffer.line_len(rows.end.previous_row()),
11729                );
11730
11731                let mut text = buffer.text_for_range(start..end).collect::<String>();
11732
11733                let insert_location = if upwards {
11734                    // When duplicating upward, we need to insert before the current line.
11735                    // If we're on the last line and it doesn't end with a newline,
11736                    // we need to add a newline before the duplicated content.
11737                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11738                        && buffer.max_point().column > 0
11739                        && !text.ends_with('\n');
11740
11741                    if needs_leading_newline {
11742                        text.insert(0, '\n');
11743                        end
11744                    } else {
11745                        text.push('\n');
11746                        Point::new(rows.end.0, 0)
11747                    }
11748                } else {
11749                    text.push('\n');
11750                    start
11751                };
11752                edits.push((insert_location..insert_location, text));
11753            } else {
11754                // duplicate character-wise
11755                let start = selection.start;
11756                let end = selection.end;
11757                let text = buffer.text_for_range(start..end).collect::<String>();
11758                edits.push((selection.end..selection.end, text));
11759            }
11760        }
11761
11762        self.transact(window, cx, |this, _, cx| {
11763            this.buffer.update(cx, |buffer, cx| {
11764                buffer.edit(edits, None, cx);
11765            });
11766
11767            this.request_autoscroll(Autoscroll::fit(), cx);
11768        });
11769    }
11770
11771    pub fn duplicate_line_up(
11772        &mut self,
11773        _: &DuplicateLineUp,
11774        window: &mut Window,
11775        cx: &mut Context<Self>,
11776    ) {
11777        self.duplicate(true, true, window, cx);
11778    }
11779
11780    pub fn duplicate_line_down(
11781        &mut self,
11782        _: &DuplicateLineDown,
11783        window: &mut Window,
11784        cx: &mut Context<Self>,
11785    ) {
11786        self.duplicate(false, true, window, cx);
11787    }
11788
11789    pub fn duplicate_selection(
11790        &mut self,
11791        _: &DuplicateSelection,
11792        window: &mut Window,
11793        cx: &mut Context<Self>,
11794    ) {
11795        self.duplicate(false, false, window, cx);
11796    }
11797
11798    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11799        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11800        if self.mode.is_single_line() {
11801            cx.propagate();
11802            return;
11803        }
11804
11805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11806        let buffer = self.buffer.read(cx).snapshot(cx);
11807
11808        let mut edits = Vec::new();
11809        let mut unfold_ranges = Vec::new();
11810        let mut refold_creases = Vec::new();
11811
11812        let selections = self.selections.all::<Point>(cx);
11813        let mut selections = selections.iter().peekable();
11814        let mut contiguous_row_selections = Vec::new();
11815        let mut new_selections = Vec::new();
11816
11817        while let Some(selection) = selections.next() {
11818            // Find all the selections that span a contiguous row range
11819            let (start_row, end_row) = consume_contiguous_rows(
11820                &mut contiguous_row_selections,
11821                selection,
11822                &display_map,
11823                &mut selections,
11824            );
11825
11826            // Move the text spanned by the row range to be before the line preceding the row range
11827            if start_row.0 > 0 {
11828                let range_to_move = Point::new(
11829                    start_row.previous_row().0,
11830                    buffer.line_len(start_row.previous_row()),
11831                )
11832                    ..Point::new(
11833                        end_row.previous_row().0,
11834                        buffer.line_len(end_row.previous_row()),
11835                    );
11836                let insertion_point = display_map
11837                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11838                    .0;
11839
11840                // Don't move lines across excerpts
11841                if buffer
11842                    .excerpt_containing(insertion_point..range_to_move.end)
11843                    .is_some()
11844                {
11845                    let text = buffer
11846                        .text_for_range(range_to_move.clone())
11847                        .flat_map(|s| s.chars())
11848                        .skip(1)
11849                        .chain(['\n'])
11850                        .collect::<String>();
11851
11852                    edits.push((
11853                        buffer.anchor_after(range_to_move.start)
11854                            ..buffer.anchor_before(range_to_move.end),
11855                        String::new(),
11856                    ));
11857                    let insertion_anchor = buffer.anchor_after(insertion_point);
11858                    edits.push((insertion_anchor..insertion_anchor, text));
11859
11860                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11861
11862                    // Move selections up
11863                    new_selections.extend(contiguous_row_selections.drain(..).map(
11864                        |mut selection| {
11865                            selection.start.row -= row_delta;
11866                            selection.end.row -= row_delta;
11867                            selection
11868                        },
11869                    ));
11870
11871                    // Move folds up
11872                    unfold_ranges.push(range_to_move.clone());
11873                    for fold in display_map.folds_in_range(
11874                        buffer.anchor_before(range_to_move.start)
11875                            ..buffer.anchor_after(range_to_move.end),
11876                    ) {
11877                        let mut start = fold.range.start.to_point(&buffer);
11878                        let mut end = fold.range.end.to_point(&buffer);
11879                        start.row -= row_delta;
11880                        end.row -= row_delta;
11881                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11882                    }
11883                }
11884            }
11885
11886            // If we didn't move line(s), preserve the existing selections
11887            new_selections.append(&mut contiguous_row_selections);
11888        }
11889
11890        self.transact(window, cx, |this, window, cx| {
11891            this.unfold_ranges(&unfold_ranges, true, true, cx);
11892            this.buffer.update(cx, |buffer, cx| {
11893                for (range, text) in edits {
11894                    buffer.edit([(range, text)], None, cx);
11895                }
11896            });
11897            this.fold_creases(refold_creases, true, window, cx);
11898            this.change_selections(Default::default(), window, cx, |s| {
11899                s.select(new_selections);
11900            })
11901        });
11902    }
11903
11904    pub fn move_line_down(
11905        &mut self,
11906        _: &MoveLineDown,
11907        window: &mut Window,
11908        cx: &mut Context<Self>,
11909    ) {
11910        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11911        if self.mode.is_single_line() {
11912            cx.propagate();
11913            return;
11914        }
11915
11916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11917        let buffer = self.buffer.read(cx).snapshot(cx);
11918
11919        let mut edits = Vec::new();
11920        let mut unfold_ranges = Vec::new();
11921        let mut refold_creases = Vec::new();
11922
11923        let selections = self.selections.all::<Point>(cx);
11924        let mut selections = selections.iter().peekable();
11925        let mut contiguous_row_selections = Vec::new();
11926        let mut new_selections = Vec::new();
11927
11928        while let Some(selection) = selections.next() {
11929            // Find all the selections that span a contiguous row range
11930            let (start_row, end_row) = consume_contiguous_rows(
11931                &mut contiguous_row_selections,
11932                selection,
11933                &display_map,
11934                &mut selections,
11935            );
11936
11937            // Move the text spanned by the row range to be after the last line of the row range
11938            if end_row.0 <= buffer.max_point().row {
11939                let range_to_move =
11940                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11941                let insertion_point = display_map
11942                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11943                    .0;
11944
11945                // Don't move lines across excerpt boundaries
11946                if buffer
11947                    .excerpt_containing(range_to_move.start..insertion_point)
11948                    .is_some()
11949                {
11950                    let mut text = String::from("\n");
11951                    text.extend(buffer.text_for_range(range_to_move.clone()));
11952                    text.pop(); // Drop trailing newline
11953                    edits.push((
11954                        buffer.anchor_after(range_to_move.start)
11955                            ..buffer.anchor_before(range_to_move.end),
11956                        String::new(),
11957                    ));
11958                    let insertion_anchor = buffer.anchor_after(insertion_point);
11959                    edits.push((insertion_anchor..insertion_anchor, text));
11960
11961                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11962
11963                    // Move selections down
11964                    new_selections.extend(contiguous_row_selections.drain(..).map(
11965                        |mut selection| {
11966                            selection.start.row += row_delta;
11967                            selection.end.row += row_delta;
11968                            selection
11969                        },
11970                    ));
11971
11972                    // Move folds down
11973                    unfold_ranges.push(range_to_move.clone());
11974                    for fold in display_map.folds_in_range(
11975                        buffer.anchor_before(range_to_move.start)
11976                            ..buffer.anchor_after(range_to_move.end),
11977                    ) {
11978                        let mut start = fold.range.start.to_point(&buffer);
11979                        let mut end = fold.range.end.to_point(&buffer);
11980                        start.row += row_delta;
11981                        end.row += row_delta;
11982                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11983                    }
11984                }
11985            }
11986
11987            // If we didn't move line(s), preserve the existing selections
11988            new_selections.append(&mut contiguous_row_selections);
11989        }
11990
11991        self.transact(window, cx, |this, window, cx| {
11992            this.unfold_ranges(&unfold_ranges, true, true, cx);
11993            this.buffer.update(cx, |buffer, cx| {
11994                for (range, text) in edits {
11995                    buffer.edit([(range, text)], None, cx);
11996                }
11997            });
11998            this.fold_creases(refold_creases, true, window, cx);
11999            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12000        });
12001    }
12002
12003    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12004        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12005        let text_layout_details = &self.text_layout_details(window);
12006        self.transact(window, cx, |this, window, cx| {
12007            let edits = this.change_selections(Default::default(), window, cx, |s| {
12008                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12009                s.move_with(|display_map, selection| {
12010                    if !selection.is_empty() {
12011                        return;
12012                    }
12013
12014                    let mut head = selection.head();
12015                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12016                    if head.column() == display_map.line_len(head.row()) {
12017                        transpose_offset = display_map
12018                            .buffer_snapshot()
12019                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12020                    }
12021
12022                    if transpose_offset == 0 {
12023                        return;
12024                    }
12025
12026                    *head.column_mut() += 1;
12027                    head = display_map.clip_point(head, Bias::Right);
12028                    let goal = SelectionGoal::HorizontalPosition(
12029                        display_map
12030                            .x_for_display_point(head, text_layout_details)
12031                            .into(),
12032                    );
12033                    selection.collapse_to(head, goal);
12034
12035                    let transpose_start = display_map
12036                        .buffer_snapshot()
12037                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12038                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12039                        let transpose_end = display_map
12040                            .buffer_snapshot()
12041                            .clip_offset(transpose_offset + 1, Bias::Right);
12042                        if let Some(ch) = display_map
12043                            .buffer_snapshot()
12044                            .chars_at(transpose_start)
12045                            .next()
12046                        {
12047                            edits.push((transpose_start..transpose_offset, String::new()));
12048                            edits.push((transpose_end..transpose_end, ch.to_string()));
12049                        }
12050                    }
12051                });
12052                edits
12053            });
12054            this.buffer
12055                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12056            let selections = this.selections.all::<usize>(cx);
12057            this.change_selections(Default::default(), window, cx, |s| {
12058                s.select(selections);
12059            });
12060        });
12061    }
12062
12063    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12065        if self.mode.is_single_line() {
12066            cx.propagate();
12067            return;
12068        }
12069
12070        self.rewrap_impl(RewrapOptions::default(), cx)
12071    }
12072
12073    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12074        let buffer = self.buffer.read(cx).snapshot(cx);
12075        let selections = self.selections.all::<Point>(cx);
12076
12077        #[derive(Clone, Debug, PartialEq)]
12078        enum CommentFormat {
12079            /// single line comment, with prefix for line
12080            Line(String),
12081            /// single line within a block comment, with prefix for line
12082            BlockLine(String),
12083            /// a single line of a block comment that includes the initial delimiter
12084            BlockCommentWithStart(BlockCommentConfig),
12085            /// a single line of a block comment that includes the ending delimiter
12086            BlockCommentWithEnd(BlockCommentConfig),
12087        }
12088
12089        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12090        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12091            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12092                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12093                .peekable();
12094
12095            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12096                row
12097            } else {
12098                return Vec::new();
12099            };
12100
12101            let language_settings = buffer.language_settings_at(selection.head(), cx);
12102            let language_scope = buffer.language_scope_at(selection.head());
12103
12104            let indent_and_prefix_for_row =
12105                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12106                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12107                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12108                        &language_scope
12109                    {
12110                        let indent_end = Point::new(row, indent.len);
12111                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12112                        let line_text_after_indent = buffer
12113                            .text_for_range(indent_end..line_end)
12114                            .collect::<String>();
12115
12116                        let is_within_comment_override = buffer
12117                            .language_scope_at(indent_end)
12118                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12119                        let comment_delimiters = if is_within_comment_override {
12120                            // we are within a comment syntax node, but we don't
12121                            // yet know what kind of comment: block, doc or line
12122                            match (
12123                                language_scope.documentation_comment(),
12124                                language_scope.block_comment(),
12125                            ) {
12126                                (Some(config), _) | (_, Some(config))
12127                                    if buffer.contains_str_at(indent_end, &config.start) =>
12128                                {
12129                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12130                                }
12131                                (Some(config), _) | (_, Some(config))
12132                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12133                                {
12134                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12135                                }
12136                                (Some(config), _) | (_, Some(config))
12137                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12138                                {
12139                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12140                                }
12141                                (_, _) => language_scope
12142                                    .line_comment_prefixes()
12143                                    .iter()
12144                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12145                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12146                            }
12147                        } else {
12148                            // we not in an overridden comment node, but we may
12149                            // be within a non-overridden line comment node
12150                            language_scope
12151                                .line_comment_prefixes()
12152                                .iter()
12153                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12154                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12155                        };
12156
12157                        let rewrap_prefix = language_scope
12158                            .rewrap_prefixes()
12159                            .iter()
12160                            .find_map(|prefix_regex| {
12161                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12162                                    if mat.start() == 0 {
12163                                        Some(mat.as_str().to_string())
12164                                    } else {
12165                                        None
12166                                    }
12167                                })
12168                            })
12169                            .flatten();
12170                        (comment_delimiters, rewrap_prefix)
12171                    } else {
12172                        (None, None)
12173                    };
12174                    (indent, comment_prefix, rewrap_prefix)
12175                };
12176
12177            let mut ranges = Vec::new();
12178            let from_empty_selection = selection.is_empty();
12179
12180            let mut current_range_start = first_row;
12181            let mut prev_row = first_row;
12182            let (
12183                mut current_range_indent,
12184                mut current_range_comment_delimiters,
12185                mut current_range_rewrap_prefix,
12186            ) = indent_and_prefix_for_row(first_row);
12187
12188            for row in non_blank_rows_iter.skip(1) {
12189                let has_paragraph_break = row > prev_row + 1;
12190
12191                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12192                    indent_and_prefix_for_row(row);
12193
12194                let has_indent_change = row_indent != current_range_indent;
12195                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12196
12197                let has_boundary_change = has_comment_change
12198                    || row_rewrap_prefix.is_some()
12199                    || (has_indent_change && current_range_comment_delimiters.is_some());
12200
12201                if has_paragraph_break || has_boundary_change {
12202                    ranges.push((
12203                        language_settings.clone(),
12204                        Point::new(current_range_start, 0)
12205                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12206                        current_range_indent,
12207                        current_range_comment_delimiters.clone(),
12208                        current_range_rewrap_prefix.clone(),
12209                        from_empty_selection,
12210                    ));
12211                    current_range_start = row;
12212                    current_range_indent = row_indent;
12213                    current_range_comment_delimiters = row_comment_delimiters;
12214                    current_range_rewrap_prefix = row_rewrap_prefix;
12215                }
12216                prev_row = row;
12217            }
12218
12219            ranges.push((
12220                language_settings.clone(),
12221                Point::new(current_range_start, 0)
12222                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12223                current_range_indent,
12224                current_range_comment_delimiters,
12225                current_range_rewrap_prefix,
12226                from_empty_selection,
12227            ));
12228
12229            ranges
12230        });
12231
12232        let mut edits = Vec::new();
12233        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12234
12235        for (
12236            language_settings,
12237            wrap_range,
12238            mut indent_size,
12239            comment_prefix,
12240            rewrap_prefix,
12241            from_empty_selection,
12242        ) in wrap_ranges
12243        {
12244            let mut start_row = wrap_range.start.row;
12245            let mut end_row = wrap_range.end.row;
12246
12247            // Skip selections that overlap with a range that has already been rewrapped.
12248            let selection_range = start_row..end_row;
12249            if rewrapped_row_ranges
12250                .iter()
12251                .any(|range| range.overlaps(&selection_range))
12252            {
12253                continue;
12254            }
12255
12256            let tab_size = language_settings.tab_size;
12257
12258            let (line_prefix, inside_comment) = match &comment_prefix {
12259                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12260                    (Some(prefix.as_str()), true)
12261                }
12262                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12263                    (Some(prefix.as_ref()), true)
12264                }
12265                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12266                    start: _,
12267                    end: _,
12268                    prefix,
12269                    tab_size,
12270                })) => {
12271                    indent_size.len += tab_size;
12272                    (Some(prefix.as_ref()), true)
12273                }
12274                None => (None, false),
12275            };
12276            let indent_prefix = indent_size.chars().collect::<String>();
12277            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12278
12279            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12280                RewrapBehavior::InComments => inside_comment,
12281                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12282                RewrapBehavior::Anywhere => true,
12283            };
12284
12285            let should_rewrap = options.override_language_settings
12286                || allow_rewrap_based_on_language
12287                || self.hard_wrap.is_some();
12288            if !should_rewrap {
12289                continue;
12290            }
12291
12292            if from_empty_selection {
12293                'expand_upwards: while start_row > 0 {
12294                    let prev_row = start_row - 1;
12295                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12296                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12297                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12298                    {
12299                        start_row = prev_row;
12300                    } else {
12301                        break 'expand_upwards;
12302                    }
12303                }
12304
12305                'expand_downwards: while end_row < buffer.max_point().row {
12306                    let next_row = end_row + 1;
12307                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12308                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12309                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12310                    {
12311                        end_row = next_row;
12312                    } else {
12313                        break 'expand_downwards;
12314                    }
12315                }
12316            }
12317
12318            let start = Point::new(start_row, 0);
12319            let start_offset = ToOffset::to_offset(&start, &buffer);
12320            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12321            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12322            let mut first_line_delimiter = None;
12323            let mut last_line_delimiter = None;
12324            let Some(lines_without_prefixes) = selection_text
12325                .lines()
12326                .enumerate()
12327                .map(|(ix, line)| {
12328                    let line_trimmed = line.trim_start();
12329                    if rewrap_prefix.is_some() && ix > 0 {
12330                        Ok(line_trimmed)
12331                    } else if let Some(
12332                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12333                            start,
12334                            prefix,
12335                            end,
12336                            tab_size,
12337                        })
12338                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12339                            start,
12340                            prefix,
12341                            end,
12342                            tab_size,
12343                        }),
12344                    ) = &comment_prefix
12345                    {
12346                        let line_trimmed = line_trimmed
12347                            .strip_prefix(start.as_ref())
12348                            .map(|s| {
12349                                let mut indent_size = indent_size;
12350                                indent_size.len -= tab_size;
12351                                let indent_prefix: String = indent_size.chars().collect();
12352                                first_line_delimiter = Some((indent_prefix, start));
12353                                s.trim_start()
12354                            })
12355                            .unwrap_or(line_trimmed);
12356                        let line_trimmed = line_trimmed
12357                            .strip_suffix(end.as_ref())
12358                            .map(|s| {
12359                                last_line_delimiter = Some(end);
12360                                s.trim_end()
12361                            })
12362                            .unwrap_or(line_trimmed);
12363                        let line_trimmed = line_trimmed
12364                            .strip_prefix(prefix.as_ref())
12365                            .unwrap_or(line_trimmed);
12366                        Ok(line_trimmed)
12367                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12368                        line_trimmed.strip_prefix(prefix).with_context(|| {
12369                            format!("line did not start with prefix {prefix:?}: {line:?}")
12370                        })
12371                    } else {
12372                        line_trimmed
12373                            .strip_prefix(&line_prefix.trim_start())
12374                            .with_context(|| {
12375                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12376                            })
12377                    }
12378                })
12379                .collect::<Result<Vec<_>, _>>()
12380                .log_err()
12381            else {
12382                continue;
12383            };
12384
12385            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12386                buffer
12387                    .language_settings_at(Point::new(start_row, 0), cx)
12388                    .preferred_line_length as usize
12389            });
12390
12391            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12392                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12393            } else {
12394                line_prefix.clone()
12395            };
12396
12397            let wrapped_text = {
12398                let mut wrapped_text = wrap_with_prefix(
12399                    line_prefix,
12400                    subsequent_lines_prefix,
12401                    lines_without_prefixes.join("\n"),
12402                    wrap_column,
12403                    tab_size,
12404                    options.preserve_existing_whitespace,
12405                );
12406
12407                if let Some((indent, delimiter)) = first_line_delimiter {
12408                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12409                }
12410                if let Some(last_line) = last_line_delimiter {
12411                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12412                }
12413
12414                wrapped_text
12415            };
12416
12417            // TODO: should always use char-based diff while still supporting cursor behavior that
12418            // matches vim.
12419            let mut diff_options = DiffOptions::default();
12420            if options.override_language_settings {
12421                diff_options.max_word_diff_len = 0;
12422                diff_options.max_word_diff_line_count = 0;
12423            } else {
12424                diff_options.max_word_diff_len = usize::MAX;
12425                diff_options.max_word_diff_line_count = usize::MAX;
12426            }
12427
12428            for (old_range, new_text) in
12429                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12430            {
12431                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12432                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12433                edits.push((edit_start..edit_end, new_text));
12434            }
12435
12436            rewrapped_row_ranges.push(start_row..=end_row);
12437        }
12438
12439        self.buffer
12440            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12441    }
12442
12443    pub fn cut_common(
12444        &mut self,
12445        cut_no_selection_line: bool,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) -> ClipboardItem {
12449        let mut text = String::new();
12450        let buffer = self.buffer.read(cx).snapshot(cx);
12451        let mut selections = self.selections.all::<Point>(cx);
12452        let mut clipboard_selections = Vec::with_capacity(selections.len());
12453        {
12454            let max_point = buffer.max_point();
12455            let mut is_first = true;
12456            for selection in &mut selections {
12457                let is_entire_line =
12458                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12459                if is_entire_line {
12460                    selection.start = Point::new(selection.start.row, 0);
12461                    if !selection.is_empty() && selection.end.column == 0 {
12462                        selection.end = cmp::min(max_point, selection.end);
12463                    } else {
12464                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12465                    }
12466                    selection.goal = SelectionGoal::None;
12467                }
12468                if is_first {
12469                    is_first = false;
12470                } else {
12471                    text += "\n";
12472                }
12473                let mut len = 0;
12474                for chunk in buffer.text_for_range(selection.start..selection.end) {
12475                    text.push_str(chunk);
12476                    len += chunk.len();
12477                }
12478                clipboard_selections.push(ClipboardSelection {
12479                    len,
12480                    is_entire_line,
12481                    first_line_indent: buffer
12482                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12483                        .len,
12484                });
12485            }
12486        }
12487
12488        self.transact(window, cx, |this, window, cx| {
12489            this.change_selections(Default::default(), window, cx, |s| {
12490                s.select(selections);
12491            });
12492            this.insert("", window, cx);
12493        });
12494        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12495    }
12496
12497    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12498        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12499        let item = self.cut_common(true, window, cx);
12500        cx.write_to_clipboard(item);
12501    }
12502
12503    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12505        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12506            s.move_with(|snapshot, sel| {
12507                if sel.is_empty() {
12508                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12509                }
12510                if sel.is_empty() {
12511                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12512                }
12513            });
12514        });
12515        let item = self.cut_common(false, window, cx);
12516        cx.set_global(KillRing(item))
12517    }
12518
12519    pub fn kill_ring_yank(
12520        &mut self,
12521        _: &KillRingYank,
12522        window: &mut Window,
12523        cx: &mut Context<Self>,
12524    ) {
12525        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12526        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12527            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12528                (kill_ring.text().to_string(), kill_ring.metadata_json())
12529            } else {
12530                return;
12531            }
12532        } else {
12533            return;
12534        };
12535        self.do_paste(&text, metadata, false, window, cx);
12536    }
12537
12538    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12539        self.do_copy(true, cx);
12540    }
12541
12542    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12543        self.do_copy(false, cx);
12544    }
12545
12546    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12547        let selections = self.selections.all::<Point>(cx);
12548        let buffer = self.buffer.read(cx).read(cx);
12549        let mut text = String::new();
12550
12551        let mut clipboard_selections = Vec::with_capacity(selections.len());
12552        {
12553            let max_point = buffer.max_point();
12554            let mut is_first = true;
12555            for selection in &selections {
12556                let mut start = selection.start;
12557                let mut end = selection.end;
12558                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12559                let mut add_trailing_newline = false;
12560                if is_entire_line {
12561                    start = Point::new(start.row, 0);
12562                    let next_line_start = Point::new(end.row + 1, 0);
12563                    if next_line_start <= max_point {
12564                        end = next_line_start;
12565                    } else {
12566                        // We're on the last line without a trailing newline.
12567                        // Copy to the end of the line and add a newline afterwards.
12568                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12569                        add_trailing_newline = true;
12570                    }
12571                }
12572
12573                let mut trimmed_selections = Vec::new();
12574                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12575                    let row = MultiBufferRow(start.row);
12576                    let first_indent = buffer.indent_size_for_line(row);
12577                    if first_indent.len == 0 || start.column > first_indent.len {
12578                        trimmed_selections.push(start..end);
12579                    } else {
12580                        trimmed_selections.push(
12581                            Point::new(row.0, first_indent.len)
12582                                ..Point::new(row.0, buffer.line_len(row)),
12583                        );
12584                        for row in start.row + 1..=end.row {
12585                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12586                            if row == end.row {
12587                                line_len = end.column;
12588                            }
12589                            if line_len == 0 {
12590                                trimmed_selections
12591                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12592                                continue;
12593                            }
12594                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12595                            if row_indent_size.len >= first_indent.len {
12596                                trimmed_selections.push(
12597                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12598                                );
12599                            } else {
12600                                trimmed_selections.clear();
12601                                trimmed_selections.push(start..end);
12602                                break;
12603                            }
12604                        }
12605                    }
12606                } else {
12607                    trimmed_selections.push(start..end);
12608                }
12609
12610                for trimmed_range in trimmed_selections {
12611                    if is_first {
12612                        is_first = false;
12613                    } else {
12614                        text += "\n";
12615                    }
12616                    let mut len = 0;
12617                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12618                        text.push_str(chunk);
12619                        len += chunk.len();
12620                    }
12621                    if add_trailing_newline {
12622                        text.push('\n');
12623                        len += 1;
12624                    }
12625                    clipboard_selections.push(ClipboardSelection {
12626                        len,
12627                        is_entire_line,
12628                        first_line_indent: buffer
12629                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12630                            .len,
12631                    });
12632                }
12633            }
12634        }
12635
12636        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12637            text,
12638            clipboard_selections,
12639        ));
12640    }
12641
12642    pub fn do_paste(
12643        &mut self,
12644        text: &String,
12645        clipboard_selections: Option<Vec<ClipboardSelection>>,
12646        handle_entire_lines: bool,
12647        window: &mut Window,
12648        cx: &mut Context<Self>,
12649    ) {
12650        if self.read_only(cx) {
12651            return;
12652        }
12653
12654        let clipboard_text = Cow::Borrowed(text.as_str());
12655
12656        self.transact(window, cx, |this, window, cx| {
12657            let had_active_edit_prediction = this.has_active_edit_prediction();
12658            let old_selections = this.selections.all::<usize>(cx);
12659            let cursor_offset = this.selections.last::<usize>(cx).head();
12660
12661            if let Some(mut clipboard_selections) = clipboard_selections {
12662                let all_selections_were_entire_line =
12663                    clipboard_selections.iter().all(|s| s.is_entire_line);
12664                let first_selection_indent_column =
12665                    clipboard_selections.first().map(|s| s.first_line_indent);
12666                if clipboard_selections.len() != old_selections.len() {
12667                    clipboard_selections.drain(..);
12668                }
12669                let mut auto_indent_on_paste = true;
12670
12671                this.buffer.update(cx, |buffer, cx| {
12672                    let snapshot = buffer.read(cx);
12673                    auto_indent_on_paste = snapshot
12674                        .language_settings_at(cursor_offset, cx)
12675                        .auto_indent_on_paste;
12676
12677                    let mut start_offset = 0;
12678                    let mut edits = Vec::new();
12679                    let mut original_indent_columns = Vec::new();
12680                    for (ix, selection) in old_selections.iter().enumerate() {
12681                        let to_insert;
12682                        let entire_line;
12683                        let original_indent_column;
12684                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12685                            let end_offset = start_offset + clipboard_selection.len;
12686                            to_insert = &clipboard_text[start_offset..end_offset];
12687                            entire_line = clipboard_selection.is_entire_line;
12688                            start_offset = end_offset + 1;
12689                            original_indent_column = Some(clipboard_selection.first_line_indent);
12690                        } else {
12691                            to_insert = &*clipboard_text;
12692                            entire_line = all_selections_were_entire_line;
12693                            original_indent_column = first_selection_indent_column
12694                        }
12695
12696                        let (range, to_insert) =
12697                            if selection.is_empty() && handle_entire_lines && entire_line {
12698                                // If the corresponding selection was empty when this slice of the
12699                                // clipboard text was written, then the entire line containing the
12700                                // selection was copied. If this selection is also currently empty,
12701                                // then paste the line before the current line of the buffer.
12702                                let column = selection.start.to_point(&snapshot).column as usize;
12703                                let line_start = selection.start - column;
12704                                (line_start..line_start, Cow::Borrowed(to_insert))
12705                            } else {
12706                                let language = snapshot.language_at(selection.head());
12707                                let range = selection.range();
12708                                if let Some(language) = language
12709                                    && language.name() == "Markdown".into()
12710                                {
12711                                    edit_for_markdown_paste(
12712                                        &snapshot,
12713                                        range,
12714                                        to_insert,
12715                                        url::Url::parse(to_insert).ok(),
12716                                    )
12717                                } else {
12718                                    (range, Cow::Borrowed(to_insert))
12719                                }
12720                            };
12721
12722                        edits.push((range, to_insert));
12723                        original_indent_columns.push(original_indent_column);
12724                    }
12725                    drop(snapshot);
12726
12727                    buffer.edit(
12728                        edits,
12729                        if auto_indent_on_paste {
12730                            Some(AutoindentMode::Block {
12731                                original_indent_columns,
12732                            })
12733                        } else {
12734                            None
12735                        },
12736                        cx,
12737                    );
12738                });
12739
12740                let selections = this.selections.all::<usize>(cx);
12741                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12742            } else {
12743                let url = url::Url::parse(&clipboard_text).ok();
12744
12745                let auto_indent_mode = if !clipboard_text.is_empty() {
12746                    Some(AutoindentMode::Block {
12747                        original_indent_columns: Vec::new(),
12748                    })
12749                } else {
12750                    None
12751                };
12752
12753                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12754                    let snapshot = buffer.snapshot(cx);
12755
12756                    let anchors = old_selections
12757                        .iter()
12758                        .map(|s| {
12759                            let anchor = snapshot.anchor_after(s.head());
12760                            s.map(|_| anchor)
12761                        })
12762                        .collect::<Vec<_>>();
12763
12764                    let mut edits = Vec::new();
12765
12766                    for selection in old_selections.iter() {
12767                        let language = snapshot.language_at(selection.head());
12768                        let range = selection.range();
12769
12770                        let (edit_range, edit_text) = if let Some(language) = language
12771                            && language.name() == "Markdown".into()
12772                        {
12773                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12774                        } else {
12775                            (range, clipboard_text.clone())
12776                        };
12777
12778                        edits.push((edit_range, edit_text));
12779                    }
12780
12781                    drop(snapshot);
12782                    buffer.edit(edits, auto_indent_mode, cx);
12783
12784                    anchors
12785                });
12786
12787                this.change_selections(Default::default(), window, cx, |s| {
12788                    s.select_anchors(selection_anchors);
12789                });
12790            }
12791
12792            let trigger_in_words =
12793                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12794
12795            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12796        });
12797    }
12798
12799    pub fn diff_clipboard_with_selection(
12800        &mut self,
12801        _: &DiffClipboardWithSelection,
12802        window: &mut Window,
12803        cx: &mut Context<Self>,
12804    ) {
12805        let selections = self.selections.all::<usize>(cx);
12806
12807        if selections.is_empty() {
12808            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12809            return;
12810        };
12811
12812        let clipboard_text = match cx.read_from_clipboard() {
12813            Some(item) => match item.entries().first() {
12814                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12815                _ => None,
12816            },
12817            None => None,
12818        };
12819
12820        let Some(clipboard_text) = clipboard_text else {
12821            log::warn!("Clipboard doesn't contain text.");
12822            return;
12823        };
12824
12825        window.dispatch_action(
12826            Box::new(DiffClipboardWithSelectionData {
12827                clipboard_text,
12828                editor: cx.entity(),
12829            }),
12830            cx,
12831        );
12832    }
12833
12834    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12835        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12836        if let Some(item) = cx.read_from_clipboard() {
12837            let entries = item.entries();
12838
12839            match entries.first() {
12840                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12841                // of all the pasted entries.
12842                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12843                    .do_paste(
12844                        clipboard_string.text(),
12845                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12846                        true,
12847                        window,
12848                        cx,
12849                    ),
12850                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12851            }
12852        }
12853    }
12854
12855    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12856        if self.read_only(cx) {
12857            return;
12858        }
12859
12860        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12861
12862        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12863            if let Some((selections, _)) =
12864                self.selection_history.transaction(transaction_id).cloned()
12865            {
12866                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12867                    s.select_anchors(selections.to_vec());
12868                });
12869            } else {
12870                log::error!(
12871                    "No entry in selection_history found for undo. \
12872                     This may correspond to a bug where undo does not update the selection. \
12873                     If this is occurring, please add details to \
12874                     https://github.com/zed-industries/zed/issues/22692"
12875                );
12876            }
12877            self.request_autoscroll(Autoscroll::fit(), cx);
12878            self.unmark_text(window, cx);
12879            self.refresh_edit_prediction(true, false, window, cx);
12880            cx.emit(EditorEvent::Edited { transaction_id });
12881            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12882        }
12883    }
12884
12885    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12886        if self.read_only(cx) {
12887            return;
12888        }
12889
12890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12891
12892        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12893            if let Some((_, Some(selections))) =
12894                self.selection_history.transaction(transaction_id).cloned()
12895            {
12896                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12897                    s.select_anchors(selections.to_vec());
12898                });
12899            } else {
12900                log::error!(
12901                    "No entry in selection_history found for redo. \
12902                     This may correspond to a bug where undo does not update the selection. \
12903                     If this is occurring, please add details to \
12904                     https://github.com/zed-industries/zed/issues/22692"
12905                );
12906            }
12907            self.request_autoscroll(Autoscroll::fit(), cx);
12908            self.unmark_text(window, cx);
12909            self.refresh_edit_prediction(true, false, window, cx);
12910            cx.emit(EditorEvent::Edited { transaction_id });
12911        }
12912    }
12913
12914    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12915        self.buffer
12916            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12917    }
12918
12919    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12920        self.buffer
12921            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12922    }
12923
12924    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12926        self.change_selections(Default::default(), window, cx, |s| {
12927            s.move_with(|map, selection| {
12928                let cursor = if selection.is_empty() {
12929                    movement::left(map, selection.start)
12930                } else {
12931                    selection.start
12932                };
12933                selection.collapse_to(cursor, SelectionGoal::None);
12934            });
12935        })
12936    }
12937
12938    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12940        self.change_selections(Default::default(), window, cx, |s| {
12941            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12942        })
12943    }
12944
12945    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12947        self.change_selections(Default::default(), window, cx, |s| {
12948            s.move_with(|map, selection| {
12949                let cursor = if selection.is_empty() {
12950                    movement::right(map, selection.end)
12951                } else {
12952                    selection.end
12953                };
12954                selection.collapse_to(cursor, SelectionGoal::None)
12955            });
12956        })
12957    }
12958
12959    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12961        self.change_selections(Default::default(), window, cx, |s| {
12962            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12963        });
12964    }
12965
12966    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12967        if self.take_rename(true, window, cx).is_some() {
12968            return;
12969        }
12970
12971        if self.mode.is_single_line() {
12972            cx.propagate();
12973            return;
12974        }
12975
12976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12977
12978        let text_layout_details = &self.text_layout_details(window);
12979        let selection_count = self.selections.count();
12980        let first_selection = self.selections.first_anchor();
12981
12982        self.change_selections(Default::default(), window, cx, |s| {
12983            s.move_with(|map, selection| {
12984                if !selection.is_empty() {
12985                    selection.goal = SelectionGoal::None;
12986                }
12987                let (cursor, goal) = movement::up(
12988                    map,
12989                    selection.start,
12990                    selection.goal,
12991                    false,
12992                    text_layout_details,
12993                );
12994                selection.collapse_to(cursor, goal);
12995            });
12996        });
12997
12998        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12999        {
13000            cx.propagate();
13001        }
13002    }
13003
13004    pub fn move_up_by_lines(
13005        &mut self,
13006        action: &MoveUpByLines,
13007        window: &mut Window,
13008        cx: &mut Context<Self>,
13009    ) {
13010        if self.take_rename(true, window, cx).is_some() {
13011            return;
13012        }
13013
13014        if self.mode.is_single_line() {
13015            cx.propagate();
13016            return;
13017        }
13018
13019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13020
13021        let text_layout_details = &self.text_layout_details(window);
13022
13023        self.change_selections(Default::default(), window, cx, |s| {
13024            s.move_with(|map, selection| {
13025                if !selection.is_empty() {
13026                    selection.goal = SelectionGoal::None;
13027                }
13028                let (cursor, goal) = movement::up_by_rows(
13029                    map,
13030                    selection.start,
13031                    action.lines,
13032                    selection.goal,
13033                    false,
13034                    text_layout_details,
13035                );
13036                selection.collapse_to(cursor, goal);
13037            });
13038        })
13039    }
13040
13041    pub fn move_down_by_lines(
13042        &mut self,
13043        action: &MoveDownByLines,
13044        window: &mut Window,
13045        cx: &mut Context<Self>,
13046    ) {
13047        if self.take_rename(true, window, cx).is_some() {
13048            return;
13049        }
13050
13051        if self.mode.is_single_line() {
13052            cx.propagate();
13053            return;
13054        }
13055
13056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13057
13058        let text_layout_details = &self.text_layout_details(window);
13059
13060        self.change_selections(Default::default(), window, cx, |s| {
13061            s.move_with(|map, selection| {
13062                if !selection.is_empty() {
13063                    selection.goal = SelectionGoal::None;
13064                }
13065                let (cursor, goal) = movement::down_by_rows(
13066                    map,
13067                    selection.start,
13068                    action.lines,
13069                    selection.goal,
13070                    false,
13071                    text_layout_details,
13072                );
13073                selection.collapse_to(cursor, goal);
13074            });
13075        })
13076    }
13077
13078    pub fn select_down_by_lines(
13079        &mut self,
13080        action: &SelectDownByLines,
13081        window: &mut Window,
13082        cx: &mut Context<Self>,
13083    ) {
13084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13085        let text_layout_details = &self.text_layout_details(window);
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_heads_with(|map, head, goal| {
13088                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13089            })
13090        })
13091    }
13092
13093    pub fn select_up_by_lines(
13094        &mut self,
13095        action: &SelectUpByLines,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100        let text_layout_details = &self.text_layout_details(window);
13101        self.change_selections(Default::default(), window, cx, |s| {
13102            s.move_heads_with(|map, head, goal| {
13103                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13104            })
13105        })
13106    }
13107
13108    pub fn select_page_up(
13109        &mut self,
13110        _: &SelectPageUp,
13111        window: &mut Window,
13112        cx: &mut Context<Self>,
13113    ) {
13114        let Some(row_count) = self.visible_row_count() else {
13115            return;
13116        };
13117
13118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13119
13120        let text_layout_details = &self.text_layout_details(window);
13121
13122        self.change_selections(Default::default(), window, cx, |s| {
13123            s.move_heads_with(|map, head, goal| {
13124                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13125            })
13126        })
13127    }
13128
13129    pub fn move_page_up(
13130        &mut self,
13131        action: &MovePageUp,
13132        window: &mut Window,
13133        cx: &mut Context<Self>,
13134    ) {
13135        if self.take_rename(true, window, cx).is_some() {
13136            return;
13137        }
13138
13139        if self
13140            .context_menu
13141            .borrow_mut()
13142            .as_mut()
13143            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13144            .unwrap_or(false)
13145        {
13146            return;
13147        }
13148
13149        if matches!(self.mode, EditorMode::SingleLine) {
13150            cx.propagate();
13151            return;
13152        }
13153
13154        let Some(row_count) = self.visible_row_count() else {
13155            return;
13156        };
13157
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13159
13160        let effects = if action.center_cursor {
13161            SelectionEffects::scroll(Autoscroll::center())
13162        } else {
13163            SelectionEffects::default()
13164        };
13165
13166        let text_layout_details = &self.text_layout_details(window);
13167
13168        self.change_selections(effects, window, cx, |s| {
13169            s.move_with(|map, selection| {
13170                if !selection.is_empty() {
13171                    selection.goal = SelectionGoal::None;
13172                }
13173                let (cursor, goal) = movement::up_by_rows(
13174                    map,
13175                    selection.end,
13176                    row_count,
13177                    selection.goal,
13178                    false,
13179                    text_layout_details,
13180                );
13181                selection.collapse_to(cursor, goal);
13182            });
13183        });
13184    }
13185
13186    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13188        let text_layout_details = &self.text_layout_details(window);
13189        self.change_selections(Default::default(), window, cx, |s| {
13190            s.move_heads_with(|map, head, goal| {
13191                movement::up(map, head, goal, false, text_layout_details)
13192            })
13193        })
13194    }
13195
13196    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13197        self.take_rename(true, window, cx);
13198
13199        if self.mode.is_single_line() {
13200            cx.propagate();
13201            return;
13202        }
13203
13204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13205
13206        let text_layout_details = &self.text_layout_details(window);
13207        let selection_count = self.selections.count();
13208        let first_selection = self.selections.first_anchor();
13209
13210        self.change_selections(Default::default(), window, cx, |s| {
13211            s.move_with(|map, selection| {
13212                if !selection.is_empty() {
13213                    selection.goal = SelectionGoal::None;
13214                }
13215                let (cursor, goal) = movement::down(
13216                    map,
13217                    selection.end,
13218                    selection.goal,
13219                    false,
13220                    text_layout_details,
13221                );
13222                selection.collapse_to(cursor, goal);
13223            });
13224        });
13225
13226        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13227        {
13228            cx.propagate();
13229        }
13230    }
13231
13232    pub fn select_page_down(
13233        &mut self,
13234        _: &SelectPageDown,
13235        window: &mut Window,
13236        cx: &mut Context<Self>,
13237    ) {
13238        let Some(row_count) = self.visible_row_count() else {
13239            return;
13240        };
13241
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243
13244        let text_layout_details = &self.text_layout_details(window);
13245
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_heads_with(|map, head, goal| {
13248                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13249            })
13250        })
13251    }
13252
13253    pub fn move_page_down(
13254        &mut self,
13255        action: &MovePageDown,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) {
13259        if self.take_rename(true, window, cx).is_some() {
13260            return;
13261        }
13262
13263        if self
13264            .context_menu
13265            .borrow_mut()
13266            .as_mut()
13267            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13268            .unwrap_or(false)
13269        {
13270            return;
13271        }
13272
13273        if matches!(self.mode, EditorMode::SingleLine) {
13274            cx.propagate();
13275            return;
13276        }
13277
13278        let Some(row_count) = self.visible_row_count() else {
13279            return;
13280        };
13281
13282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13283
13284        let effects = if action.center_cursor {
13285            SelectionEffects::scroll(Autoscroll::center())
13286        } else {
13287            SelectionEffects::default()
13288        };
13289
13290        let text_layout_details = &self.text_layout_details(window);
13291        self.change_selections(effects, window, cx, |s| {
13292            s.move_with(|map, selection| {
13293                if !selection.is_empty() {
13294                    selection.goal = SelectionGoal::None;
13295                }
13296                let (cursor, goal) = movement::down_by_rows(
13297                    map,
13298                    selection.end,
13299                    row_count,
13300                    selection.goal,
13301                    false,
13302                    text_layout_details,
13303                );
13304                selection.collapse_to(cursor, goal);
13305            });
13306        });
13307    }
13308
13309    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13311        let text_layout_details = &self.text_layout_details(window);
13312        self.change_selections(Default::default(), window, cx, |s| {
13313            s.move_heads_with(|map, head, goal| {
13314                movement::down(map, head, goal, false, text_layout_details)
13315            })
13316        });
13317    }
13318
13319    pub fn context_menu_first(
13320        &mut self,
13321        _: &ContextMenuFirst,
13322        window: &mut Window,
13323        cx: &mut Context<Self>,
13324    ) {
13325        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13326            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13327        }
13328    }
13329
13330    pub fn context_menu_prev(
13331        &mut self,
13332        _: &ContextMenuPrevious,
13333        window: &mut Window,
13334        cx: &mut Context<Self>,
13335    ) {
13336        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13337            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13338        }
13339    }
13340
13341    pub fn context_menu_next(
13342        &mut self,
13343        _: &ContextMenuNext,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13348            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13349        }
13350    }
13351
13352    pub fn context_menu_last(
13353        &mut self,
13354        _: &ContextMenuLast,
13355        window: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13359            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13360        }
13361    }
13362
13363    pub fn signature_help_prev(
13364        &mut self,
13365        _: &SignatureHelpPrevious,
13366        _: &mut Window,
13367        cx: &mut Context<Self>,
13368    ) {
13369        if let Some(popover) = self.signature_help_state.popover_mut() {
13370            if popover.current_signature == 0 {
13371                popover.current_signature = popover.signatures.len() - 1;
13372            } else {
13373                popover.current_signature -= 1;
13374            }
13375            cx.notify();
13376        }
13377    }
13378
13379    pub fn signature_help_next(
13380        &mut self,
13381        _: &SignatureHelpNext,
13382        _: &mut Window,
13383        cx: &mut Context<Self>,
13384    ) {
13385        if let Some(popover) = self.signature_help_state.popover_mut() {
13386            if popover.current_signature + 1 == popover.signatures.len() {
13387                popover.current_signature = 0;
13388            } else {
13389                popover.current_signature += 1;
13390            }
13391            cx.notify();
13392        }
13393    }
13394
13395    pub fn move_to_previous_word_start(
13396        &mut self,
13397        _: &MoveToPreviousWordStart,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) {
13401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13402        self.change_selections(Default::default(), window, cx, |s| {
13403            s.move_cursors_with(|map, head, _| {
13404                (
13405                    movement::previous_word_start(map, head),
13406                    SelectionGoal::None,
13407                )
13408            });
13409        })
13410    }
13411
13412    pub fn move_to_previous_subword_start(
13413        &mut self,
13414        _: &MoveToPreviousSubwordStart,
13415        window: &mut Window,
13416        cx: &mut Context<Self>,
13417    ) {
13418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13419        self.change_selections(Default::default(), window, cx, |s| {
13420            s.move_cursors_with(|map, head, _| {
13421                (
13422                    movement::previous_subword_start(map, head),
13423                    SelectionGoal::None,
13424                )
13425            });
13426        })
13427    }
13428
13429    pub fn select_to_previous_word_start(
13430        &mut self,
13431        _: &SelectToPreviousWordStart,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) {
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13436        self.change_selections(Default::default(), window, cx, |s| {
13437            s.move_heads_with(|map, head, _| {
13438                (
13439                    movement::previous_word_start(map, head),
13440                    SelectionGoal::None,
13441                )
13442            });
13443        })
13444    }
13445
13446    pub fn select_to_previous_subword_start(
13447        &mut self,
13448        _: &SelectToPreviousSubwordStart,
13449        window: &mut Window,
13450        cx: &mut Context<Self>,
13451    ) {
13452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13453        self.change_selections(Default::default(), window, cx, |s| {
13454            s.move_heads_with(|map, head, _| {
13455                (
13456                    movement::previous_subword_start(map, head),
13457                    SelectionGoal::None,
13458                )
13459            });
13460        })
13461    }
13462
13463    pub fn delete_to_previous_word_start(
13464        &mut self,
13465        action: &DeleteToPreviousWordStart,
13466        window: &mut Window,
13467        cx: &mut Context<Self>,
13468    ) {
13469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13470        self.transact(window, cx, |this, window, cx| {
13471            this.select_autoclose_pair(window, cx);
13472            this.change_selections(Default::default(), window, cx, |s| {
13473                s.move_with(|map, selection| {
13474                    if selection.is_empty() {
13475                        let mut cursor = if action.ignore_newlines {
13476                            movement::previous_word_start(map, selection.head())
13477                        } else {
13478                            movement::previous_word_start_or_newline(map, selection.head())
13479                        };
13480                        cursor = movement::adjust_greedy_deletion(
13481                            map,
13482                            selection.head(),
13483                            cursor,
13484                            action.ignore_brackets,
13485                        );
13486                        selection.set_head(cursor, SelectionGoal::None);
13487                    }
13488                });
13489            });
13490            this.insert("", window, cx);
13491        });
13492    }
13493
13494    pub fn delete_to_previous_subword_start(
13495        &mut self,
13496        _: &DeleteToPreviousSubwordStart,
13497        window: &mut Window,
13498        cx: &mut Context<Self>,
13499    ) {
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13501        self.transact(window, cx, |this, window, cx| {
13502            this.select_autoclose_pair(window, cx);
13503            this.change_selections(Default::default(), window, cx, |s| {
13504                s.move_with(|map, selection| {
13505                    if selection.is_empty() {
13506                        let mut cursor = movement::previous_subword_start(map, selection.head());
13507                        cursor =
13508                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13509                        selection.set_head(cursor, SelectionGoal::None);
13510                    }
13511                });
13512            });
13513            this.insert("", window, cx);
13514        });
13515    }
13516
13517    pub fn move_to_next_word_end(
13518        &mut self,
13519        _: &MoveToNextWordEnd,
13520        window: &mut Window,
13521        cx: &mut Context<Self>,
13522    ) {
13523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13524        self.change_selections(Default::default(), window, cx, |s| {
13525            s.move_cursors_with(|map, head, _| {
13526                (movement::next_word_end(map, head), SelectionGoal::None)
13527            });
13528        })
13529    }
13530
13531    pub fn move_to_next_subword_end(
13532        &mut self,
13533        _: &MoveToNextSubwordEnd,
13534        window: &mut Window,
13535        cx: &mut Context<Self>,
13536    ) {
13537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13538        self.change_selections(Default::default(), window, cx, |s| {
13539            s.move_cursors_with(|map, head, _| {
13540                (movement::next_subword_end(map, head), SelectionGoal::None)
13541            });
13542        })
13543    }
13544
13545    pub fn select_to_next_word_end(
13546        &mut self,
13547        _: &SelectToNextWordEnd,
13548        window: &mut Window,
13549        cx: &mut Context<Self>,
13550    ) {
13551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.move_heads_with(|map, head, _| {
13554                (movement::next_word_end(map, head), SelectionGoal::None)
13555            });
13556        })
13557    }
13558
13559    pub fn select_to_next_subword_end(
13560        &mut self,
13561        _: &SelectToNextSubwordEnd,
13562        window: &mut Window,
13563        cx: &mut Context<Self>,
13564    ) {
13565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13566        self.change_selections(Default::default(), window, cx, |s| {
13567            s.move_heads_with(|map, head, _| {
13568                (movement::next_subword_end(map, head), SelectionGoal::None)
13569            });
13570        })
13571    }
13572
13573    pub fn delete_to_next_word_end(
13574        &mut self,
13575        action: &DeleteToNextWordEnd,
13576        window: &mut Window,
13577        cx: &mut Context<Self>,
13578    ) {
13579        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13580        self.transact(window, cx, |this, window, cx| {
13581            this.change_selections(Default::default(), window, cx, |s| {
13582                s.move_with(|map, selection| {
13583                    if selection.is_empty() {
13584                        let mut cursor = if action.ignore_newlines {
13585                            movement::next_word_end(map, selection.head())
13586                        } else {
13587                            movement::next_word_end_or_newline(map, selection.head())
13588                        };
13589                        cursor = movement::adjust_greedy_deletion(
13590                            map,
13591                            selection.head(),
13592                            cursor,
13593                            action.ignore_brackets,
13594                        );
13595                        selection.set_head(cursor, SelectionGoal::None);
13596                    }
13597                });
13598            });
13599            this.insert("", window, cx);
13600        });
13601    }
13602
13603    pub fn delete_to_next_subword_end(
13604        &mut self,
13605        _: &DeleteToNextSubwordEnd,
13606        window: &mut Window,
13607        cx: &mut Context<Self>,
13608    ) {
13609        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13610        self.transact(window, cx, |this, window, cx| {
13611            this.change_selections(Default::default(), window, cx, |s| {
13612                s.move_with(|map, selection| {
13613                    if selection.is_empty() {
13614                        let mut cursor = movement::next_subword_end(map, selection.head());
13615                        cursor =
13616                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13617                        selection.set_head(cursor, SelectionGoal::None);
13618                    }
13619                });
13620            });
13621            this.insert("", window, cx);
13622        });
13623    }
13624
13625    pub fn move_to_beginning_of_line(
13626        &mut self,
13627        action: &MoveToBeginningOfLine,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_cursors_with(|map, head, _| {
13634                (
13635                    movement::indented_line_beginning(
13636                        map,
13637                        head,
13638                        action.stop_at_soft_wraps,
13639                        action.stop_at_indent,
13640                    ),
13641                    SelectionGoal::None,
13642                )
13643            });
13644        })
13645    }
13646
13647    pub fn select_to_beginning_of_line(
13648        &mut self,
13649        action: &SelectToBeginningOfLine,
13650        window: &mut Window,
13651        cx: &mut Context<Self>,
13652    ) {
13653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13654        self.change_selections(Default::default(), window, cx, |s| {
13655            s.move_heads_with(|map, head, _| {
13656                (
13657                    movement::indented_line_beginning(
13658                        map,
13659                        head,
13660                        action.stop_at_soft_wraps,
13661                        action.stop_at_indent,
13662                    ),
13663                    SelectionGoal::None,
13664                )
13665            });
13666        });
13667    }
13668
13669    pub fn delete_to_beginning_of_line(
13670        &mut self,
13671        action: &DeleteToBeginningOfLine,
13672        window: &mut Window,
13673        cx: &mut Context<Self>,
13674    ) {
13675        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13676        self.transact(window, cx, |this, window, cx| {
13677            this.change_selections(Default::default(), window, cx, |s| {
13678                s.move_with(|_, selection| {
13679                    selection.reversed = true;
13680                });
13681            });
13682
13683            this.select_to_beginning_of_line(
13684                &SelectToBeginningOfLine {
13685                    stop_at_soft_wraps: false,
13686                    stop_at_indent: action.stop_at_indent,
13687                },
13688                window,
13689                cx,
13690            );
13691            this.backspace(&Backspace, window, cx);
13692        });
13693    }
13694
13695    pub fn move_to_end_of_line(
13696        &mut self,
13697        action: &MoveToEndOfLine,
13698        window: &mut Window,
13699        cx: &mut Context<Self>,
13700    ) {
13701        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13702        self.change_selections(Default::default(), window, cx, |s| {
13703            s.move_cursors_with(|map, head, _| {
13704                (
13705                    movement::line_end(map, head, action.stop_at_soft_wraps),
13706                    SelectionGoal::None,
13707                )
13708            });
13709        })
13710    }
13711
13712    pub fn select_to_end_of_line(
13713        &mut self,
13714        action: &SelectToEndOfLine,
13715        window: &mut Window,
13716        cx: &mut Context<Self>,
13717    ) {
13718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.move_heads_with(|map, head, _| {
13721                (
13722                    movement::line_end(map, head, action.stop_at_soft_wraps),
13723                    SelectionGoal::None,
13724                )
13725            });
13726        })
13727    }
13728
13729    pub fn delete_to_end_of_line(
13730        &mut self,
13731        _: &DeleteToEndOfLine,
13732        window: &mut Window,
13733        cx: &mut Context<Self>,
13734    ) {
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13736        self.transact(window, cx, |this, window, cx| {
13737            this.select_to_end_of_line(
13738                &SelectToEndOfLine {
13739                    stop_at_soft_wraps: false,
13740                },
13741                window,
13742                cx,
13743            );
13744            this.delete(&Delete, window, cx);
13745        });
13746    }
13747
13748    pub fn cut_to_end_of_line(
13749        &mut self,
13750        action: &CutToEndOfLine,
13751        window: &mut Window,
13752        cx: &mut Context<Self>,
13753    ) {
13754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13755        self.transact(window, cx, |this, window, cx| {
13756            this.select_to_end_of_line(
13757                &SelectToEndOfLine {
13758                    stop_at_soft_wraps: false,
13759                },
13760                window,
13761                cx,
13762            );
13763            if !action.stop_at_newlines {
13764                this.change_selections(Default::default(), window, cx, |s| {
13765                    s.move_with(|_, sel| {
13766                        if sel.is_empty() {
13767                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13768                        }
13769                    });
13770                });
13771            }
13772            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13773            let item = this.cut_common(false, window, cx);
13774            cx.write_to_clipboard(item);
13775        });
13776    }
13777
13778    pub fn move_to_start_of_paragraph(
13779        &mut self,
13780        _: &MoveToStartOfParagraph,
13781        window: &mut Window,
13782        cx: &mut Context<Self>,
13783    ) {
13784        if matches!(self.mode, EditorMode::SingleLine) {
13785            cx.propagate();
13786            return;
13787        }
13788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13789        self.change_selections(Default::default(), window, cx, |s| {
13790            s.move_with(|map, selection| {
13791                selection.collapse_to(
13792                    movement::start_of_paragraph(map, selection.head(), 1),
13793                    SelectionGoal::None,
13794                )
13795            });
13796        })
13797    }
13798
13799    pub fn move_to_end_of_paragraph(
13800        &mut self,
13801        _: &MoveToEndOfParagraph,
13802        window: &mut Window,
13803        cx: &mut Context<Self>,
13804    ) {
13805        if matches!(self.mode, EditorMode::SingleLine) {
13806            cx.propagate();
13807            return;
13808        }
13809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13810        self.change_selections(Default::default(), window, cx, |s| {
13811            s.move_with(|map, selection| {
13812                selection.collapse_to(
13813                    movement::end_of_paragraph(map, selection.head(), 1),
13814                    SelectionGoal::None,
13815                )
13816            });
13817        })
13818    }
13819
13820    pub fn select_to_start_of_paragraph(
13821        &mut self,
13822        _: &SelectToStartOfParagraph,
13823        window: &mut Window,
13824        cx: &mut Context<Self>,
13825    ) {
13826        if matches!(self.mode, EditorMode::SingleLine) {
13827            cx.propagate();
13828            return;
13829        }
13830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13831        self.change_selections(Default::default(), window, cx, |s| {
13832            s.move_heads_with(|map, head, _| {
13833                (
13834                    movement::start_of_paragraph(map, head, 1),
13835                    SelectionGoal::None,
13836                )
13837            });
13838        })
13839    }
13840
13841    pub fn select_to_end_of_paragraph(
13842        &mut self,
13843        _: &SelectToEndOfParagraph,
13844        window: &mut Window,
13845        cx: &mut Context<Self>,
13846    ) {
13847        if matches!(self.mode, EditorMode::SingleLine) {
13848            cx.propagate();
13849            return;
13850        }
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13852        self.change_selections(Default::default(), window, cx, |s| {
13853            s.move_heads_with(|map, head, _| {
13854                (
13855                    movement::end_of_paragraph(map, head, 1),
13856                    SelectionGoal::None,
13857                )
13858            });
13859        })
13860    }
13861
13862    pub fn move_to_start_of_excerpt(
13863        &mut self,
13864        _: &MoveToStartOfExcerpt,
13865        window: &mut Window,
13866        cx: &mut Context<Self>,
13867    ) {
13868        if matches!(self.mode, EditorMode::SingleLine) {
13869            cx.propagate();
13870            return;
13871        }
13872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13873        self.change_selections(Default::default(), window, cx, |s| {
13874            s.move_with(|map, selection| {
13875                selection.collapse_to(
13876                    movement::start_of_excerpt(
13877                        map,
13878                        selection.head(),
13879                        workspace::searchable::Direction::Prev,
13880                    ),
13881                    SelectionGoal::None,
13882                )
13883            });
13884        })
13885    }
13886
13887    pub fn move_to_start_of_next_excerpt(
13888        &mut self,
13889        _: &MoveToStartOfNextExcerpt,
13890        window: &mut Window,
13891        cx: &mut Context<Self>,
13892    ) {
13893        if matches!(self.mode, EditorMode::SingleLine) {
13894            cx.propagate();
13895            return;
13896        }
13897
13898        self.change_selections(Default::default(), window, cx, |s| {
13899            s.move_with(|map, selection| {
13900                selection.collapse_to(
13901                    movement::start_of_excerpt(
13902                        map,
13903                        selection.head(),
13904                        workspace::searchable::Direction::Next,
13905                    ),
13906                    SelectionGoal::None,
13907                )
13908            });
13909        })
13910    }
13911
13912    pub fn move_to_end_of_excerpt(
13913        &mut self,
13914        _: &MoveToEndOfExcerpt,
13915        window: &mut Window,
13916        cx: &mut Context<Self>,
13917    ) {
13918        if matches!(self.mode, EditorMode::SingleLine) {
13919            cx.propagate();
13920            return;
13921        }
13922        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13923        self.change_selections(Default::default(), window, cx, |s| {
13924            s.move_with(|map, selection| {
13925                selection.collapse_to(
13926                    movement::end_of_excerpt(
13927                        map,
13928                        selection.head(),
13929                        workspace::searchable::Direction::Next,
13930                    ),
13931                    SelectionGoal::None,
13932                )
13933            });
13934        })
13935    }
13936
13937    pub fn move_to_end_of_previous_excerpt(
13938        &mut self,
13939        _: &MoveToEndOfPreviousExcerpt,
13940        window: &mut Window,
13941        cx: &mut Context<Self>,
13942    ) {
13943        if matches!(self.mode, EditorMode::SingleLine) {
13944            cx.propagate();
13945            return;
13946        }
13947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13948        self.change_selections(Default::default(), window, cx, |s| {
13949            s.move_with(|map, selection| {
13950                selection.collapse_to(
13951                    movement::end_of_excerpt(
13952                        map,
13953                        selection.head(),
13954                        workspace::searchable::Direction::Prev,
13955                    ),
13956                    SelectionGoal::None,
13957                )
13958            });
13959        })
13960    }
13961
13962    pub fn select_to_start_of_excerpt(
13963        &mut self,
13964        _: &SelectToStartOfExcerpt,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        if matches!(self.mode, EditorMode::SingleLine) {
13969            cx.propagate();
13970            return;
13971        }
13972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13973        self.change_selections(Default::default(), window, cx, |s| {
13974            s.move_heads_with(|map, head, _| {
13975                (
13976                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13977                    SelectionGoal::None,
13978                )
13979            });
13980        })
13981    }
13982
13983    pub fn select_to_start_of_next_excerpt(
13984        &mut self,
13985        _: &SelectToStartOfNextExcerpt,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        if matches!(self.mode, EditorMode::SingleLine) {
13990            cx.propagate();
13991            return;
13992        }
13993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13994        self.change_selections(Default::default(), window, cx, |s| {
13995            s.move_heads_with(|map, head, _| {
13996                (
13997                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13998                    SelectionGoal::None,
13999                )
14000            });
14001        })
14002    }
14003
14004    pub fn select_to_end_of_excerpt(
14005        &mut self,
14006        _: &SelectToEndOfExcerpt,
14007        window: &mut Window,
14008        cx: &mut Context<Self>,
14009    ) {
14010        if matches!(self.mode, EditorMode::SingleLine) {
14011            cx.propagate();
14012            return;
14013        }
14014        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14015        self.change_selections(Default::default(), window, cx, |s| {
14016            s.move_heads_with(|map, head, _| {
14017                (
14018                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14019                    SelectionGoal::None,
14020                )
14021            });
14022        })
14023    }
14024
14025    pub fn select_to_end_of_previous_excerpt(
14026        &mut self,
14027        _: &SelectToEndOfPreviousExcerpt,
14028        window: &mut Window,
14029        cx: &mut Context<Self>,
14030    ) {
14031        if matches!(self.mode, EditorMode::SingleLine) {
14032            cx.propagate();
14033            return;
14034        }
14035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14036        self.change_selections(Default::default(), window, cx, |s| {
14037            s.move_heads_with(|map, head, _| {
14038                (
14039                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14040                    SelectionGoal::None,
14041                )
14042            });
14043        })
14044    }
14045
14046    pub fn move_to_beginning(
14047        &mut self,
14048        _: &MoveToBeginning,
14049        window: &mut Window,
14050        cx: &mut Context<Self>,
14051    ) {
14052        if matches!(self.mode, EditorMode::SingleLine) {
14053            cx.propagate();
14054            return;
14055        }
14056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14057        self.change_selections(Default::default(), window, cx, |s| {
14058            s.select_ranges(vec![0..0]);
14059        });
14060    }
14061
14062    pub fn select_to_beginning(
14063        &mut self,
14064        _: &SelectToBeginning,
14065        window: &mut Window,
14066        cx: &mut Context<Self>,
14067    ) {
14068        let mut selection = self.selections.last::<Point>(cx);
14069        selection.set_head(Point::zero(), SelectionGoal::None);
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071        self.change_selections(Default::default(), window, cx, |s| {
14072            s.select(vec![selection]);
14073        });
14074    }
14075
14076    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14077        if matches!(self.mode, EditorMode::SingleLine) {
14078            cx.propagate();
14079            return;
14080        }
14081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14082        let cursor = self.buffer.read(cx).read(cx).len();
14083        self.change_selections(Default::default(), window, cx, |s| {
14084            s.select_ranges(vec![cursor..cursor])
14085        });
14086    }
14087
14088    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14089        self.nav_history = nav_history;
14090    }
14091
14092    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14093        self.nav_history.as_ref()
14094    }
14095
14096    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14097        self.push_to_nav_history(
14098            self.selections.newest_anchor().head(),
14099            None,
14100            false,
14101            true,
14102            cx,
14103        );
14104    }
14105
14106    fn push_to_nav_history(
14107        &mut self,
14108        cursor_anchor: Anchor,
14109        new_position: Option<Point>,
14110        is_deactivate: bool,
14111        always: bool,
14112        cx: &mut Context<Self>,
14113    ) {
14114        if let Some(nav_history) = self.nav_history.as_mut() {
14115            let buffer = self.buffer.read(cx).read(cx);
14116            let cursor_position = cursor_anchor.to_point(&buffer);
14117            let scroll_state = self.scroll_manager.anchor();
14118            let scroll_top_row = scroll_state.top_row(&buffer);
14119            drop(buffer);
14120
14121            if let Some(new_position) = new_position {
14122                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14123                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14124                    return;
14125                }
14126            }
14127
14128            nav_history.push(
14129                Some(NavigationData {
14130                    cursor_anchor,
14131                    cursor_position,
14132                    scroll_anchor: scroll_state,
14133                    scroll_top_row,
14134                }),
14135                cx,
14136            );
14137            cx.emit(EditorEvent::PushedToNavHistory {
14138                anchor: cursor_anchor,
14139                is_deactivate,
14140            })
14141        }
14142    }
14143
14144    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14146        let buffer = self.buffer.read(cx).snapshot(cx);
14147        let mut selection = self.selections.first::<usize>(cx);
14148        selection.set_head(buffer.len(), SelectionGoal::None);
14149        self.change_selections(Default::default(), window, cx, |s| {
14150            s.select(vec![selection]);
14151        });
14152    }
14153
14154    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14156        let end = self.buffer.read(cx).read(cx).len();
14157        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14158            s.select_ranges(vec![0..end]);
14159        });
14160    }
14161
14162    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14164        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14165        let mut selections = self.selections.all::<Point>(cx);
14166        let max_point = display_map.buffer_snapshot().max_point();
14167        for selection in &mut selections {
14168            let rows = selection.spanned_rows(true, &display_map);
14169            selection.start = Point::new(rows.start.0, 0);
14170            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14171            selection.reversed = false;
14172        }
14173        self.change_selections(Default::default(), window, cx, |s| {
14174            s.select(selections);
14175        });
14176    }
14177
14178    pub fn split_selection_into_lines(
14179        &mut self,
14180        action: &SplitSelectionIntoLines,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        let selections = self
14185            .selections
14186            .all::<Point>(cx)
14187            .into_iter()
14188            .map(|selection| selection.start..selection.end)
14189            .collect::<Vec<_>>();
14190        self.unfold_ranges(&selections, true, true, cx);
14191
14192        let mut new_selection_ranges = Vec::new();
14193        {
14194            let buffer = self.buffer.read(cx).read(cx);
14195            for selection in selections {
14196                for row in selection.start.row..selection.end.row {
14197                    let line_start = Point::new(row, 0);
14198                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14199
14200                    if action.keep_selections {
14201                        // Keep the selection range for each line
14202                        let selection_start = if row == selection.start.row {
14203                            selection.start
14204                        } else {
14205                            line_start
14206                        };
14207                        new_selection_ranges.push(selection_start..line_end);
14208                    } else {
14209                        // Collapse to cursor at end of line
14210                        new_selection_ranges.push(line_end..line_end);
14211                    }
14212                }
14213
14214                let is_multiline_selection = selection.start.row != selection.end.row;
14215                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14216                // so this action feels more ergonomic when paired with other selection operations
14217                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14218                if !should_skip_last {
14219                    if action.keep_selections {
14220                        if is_multiline_selection {
14221                            let line_start = Point::new(selection.end.row, 0);
14222                            new_selection_ranges.push(line_start..selection.end);
14223                        } else {
14224                            new_selection_ranges.push(selection.start..selection.end);
14225                        }
14226                    } else {
14227                        new_selection_ranges.push(selection.end..selection.end);
14228                    }
14229                }
14230            }
14231        }
14232        self.change_selections(Default::default(), window, cx, |s| {
14233            s.select_ranges(new_selection_ranges);
14234        });
14235    }
14236
14237    pub fn add_selection_above(
14238        &mut self,
14239        _: &AddSelectionAbove,
14240        window: &mut Window,
14241        cx: &mut Context<Self>,
14242    ) {
14243        self.add_selection(true, window, cx);
14244    }
14245
14246    pub fn add_selection_below(
14247        &mut self,
14248        _: &AddSelectionBelow,
14249        window: &mut Window,
14250        cx: &mut Context<Self>,
14251    ) {
14252        self.add_selection(false, window, cx);
14253    }
14254
14255    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14257
14258        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14259        let all_selections = self.selections.all::<Point>(cx);
14260        let text_layout_details = self.text_layout_details(window);
14261
14262        let (mut columnar_selections, new_selections_to_columnarize) = {
14263            if let Some(state) = self.add_selections_state.as_ref() {
14264                let columnar_selection_ids: HashSet<_> = state
14265                    .groups
14266                    .iter()
14267                    .flat_map(|group| group.stack.iter())
14268                    .copied()
14269                    .collect();
14270
14271                all_selections
14272                    .into_iter()
14273                    .partition(|s| columnar_selection_ids.contains(&s.id))
14274            } else {
14275                (Vec::new(), all_selections)
14276            }
14277        };
14278
14279        let mut state = self
14280            .add_selections_state
14281            .take()
14282            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14283
14284        for selection in new_selections_to_columnarize {
14285            let range = selection.display_range(&display_map).sorted();
14286            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14287            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14288            let positions = start_x.min(end_x)..start_x.max(end_x);
14289            let mut stack = Vec::new();
14290            for row in range.start.row().0..=range.end.row().0 {
14291                if let Some(selection) = self.selections.build_columnar_selection(
14292                    &display_map,
14293                    DisplayRow(row),
14294                    &positions,
14295                    selection.reversed,
14296                    &text_layout_details,
14297                ) {
14298                    stack.push(selection.id);
14299                    columnar_selections.push(selection);
14300                }
14301            }
14302            if !stack.is_empty() {
14303                if above {
14304                    stack.reverse();
14305                }
14306                state.groups.push(AddSelectionsGroup { above, stack });
14307            }
14308        }
14309
14310        let mut final_selections = Vec::new();
14311        let end_row = if above {
14312            DisplayRow(0)
14313        } else {
14314            display_map.max_point().row()
14315        };
14316
14317        let mut last_added_item_per_group = HashMap::default();
14318        for group in state.groups.iter_mut() {
14319            if let Some(last_id) = group.stack.last() {
14320                last_added_item_per_group.insert(*last_id, group);
14321            }
14322        }
14323
14324        for selection in columnar_selections {
14325            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14326                if above == group.above {
14327                    let range = selection.display_range(&display_map).sorted();
14328                    debug_assert_eq!(range.start.row(), range.end.row());
14329                    let mut row = range.start.row();
14330                    let positions =
14331                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14332                            Pixels::from(start)..Pixels::from(end)
14333                        } else {
14334                            let start_x =
14335                                display_map.x_for_display_point(range.start, &text_layout_details);
14336                            let end_x =
14337                                display_map.x_for_display_point(range.end, &text_layout_details);
14338                            start_x.min(end_x)..start_x.max(end_x)
14339                        };
14340
14341                    let mut maybe_new_selection = None;
14342                    while row != end_row {
14343                        if above {
14344                            row.0 -= 1;
14345                        } else {
14346                            row.0 += 1;
14347                        }
14348                        if let Some(new_selection) = self.selections.build_columnar_selection(
14349                            &display_map,
14350                            row,
14351                            &positions,
14352                            selection.reversed,
14353                            &text_layout_details,
14354                        ) {
14355                            maybe_new_selection = Some(new_selection);
14356                            break;
14357                        }
14358                    }
14359
14360                    if let Some(new_selection) = maybe_new_selection {
14361                        group.stack.push(new_selection.id);
14362                        if above {
14363                            final_selections.push(new_selection);
14364                            final_selections.push(selection);
14365                        } else {
14366                            final_selections.push(selection);
14367                            final_selections.push(new_selection);
14368                        }
14369                    } else {
14370                        final_selections.push(selection);
14371                    }
14372                } else {
14373                    group.stack.pop();
14374                }
14375            } else {
14376                final_selections.push(selection);
14377            }
14378        }
14379
14380        self.change_selections(Default::default(), window, cx, |s| {
14381            s.select(final_selections);
14382        });
14383
14384        let final_selection_ids: HashSet<_> = self
14385            .selections
14386            .all::<Point>(cx)
14387            .iter()
14388            .map(|s| s.id)
14389            .collect();
14390        state.groups.retain_mut(|group| {
14391            // selections might get merged above so we remove invalid items from stacks
14392            group.stack.retain(|id| final_selection_ids.contains(id));
14393
14394            // single selection in stack can be treated as initial state
14395            group.stack.len() > 1
14396        });
14397
14398        if !state.groups.is_empty() {
14399            self.add_selections_state = Some(state);
14400        }
14401    }
14402
14403    fn select_match_ranges(
14404        &mut self,
14405        range: Range<usize>,
14406        reversed: bool,
14407        replace_newest: bool,
14408        auto_scroll: Option<Autoscroll>,
14409        window: &mut Window,
14410        cx: &mut Context<Editor>,
14411    ) {
14412        self.unfold_ranges(
14413            std::slice::from_ref(&range),
14414            false,
14415            auto_scroll.is_some(),
14416            cx,
14417        );
14418        let effects = if let Some(scroll) = auto_scroll {
14419            SelectionEffects::scroll(scroll)
14420        } else {
14421            SelectionEffects::no_scroll()
14422        };
14423        self.change_selections(effects, window, cx, |s| {
14424            if replace_newest {
14425                s.delete(s.newest_anchor().id);
14426            }
14427            if reversed {
14428                s.insert_range(range.end..range.start);
14429            } else {
14430                s.insert_range(range);
14431            }
14432        });
14433    }
14434
14435    pub fn select_next_match_internal(
14436        &mut self,
14437        display_map: &DisplaySnapshot,
14438        replace_newest: bool,
14439        autoscroll: Option<Autoscroll>,
14440        window: &mut Window,
14441        cx: &mut Context<Self>,
14442    ) -> Result<()> {
14443        let buffer = display_map.buffer_snapshot();
14444        let mut selections = self.selections.all::<usize>(cx);
14445        if let Some(mut select_next_state) = self.select_next_state.take() {
14446            let query = &select_next_state.query;
14447            if !select_next_state.done {
14448                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14449                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14450                let mut next_selected_range = None;
14451
14452                // Collect and sort selection ranges for efficient overlap checking
14453                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14454                selection_ranges.sort_by_key(|r| r.start);
14455
14456                let bytes_after_last_selection =
14457                    buffer.bytes_in_range(last_selection.end..buffer.len());
14458                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14459                let query_matches = query
14460                    .stream_find_iter(bytes_after_last_selection)
14461                    .map(|result| (last_selection.end, result))
14462                    .chain(
14463                        query
14464                            .stream_find_iter(bytes_before_first_selection)
14465                            .map(|result| (0, result)),
14466                    );
14467
14468                for (start_offset, query_match) in query_matches {
14469                    let query_match = query_match.unwrap(); // can only fail due to I/O
14470                    let offset_range =
14471                        start_offset + query_match.start()..start_offset + query_match.end();
14472
14473                    if !select_next_state.wordwise
14474                        || (!buffer.is_inside_word(offset_range.start, None)
14475                            && !buffer.is_inside_word(offset_range.end, None))
14476                    {
14477                        // Use binary search to check for overlap (O(log n))
14478                        let overlaps = selection_ranges
14479                            .binary_search_by(|range| {
14480                                if range.end <= offset_range.start {
14481                                    std::cmp::Ordering::Less
14482                                } else if range.start >= offset_range.end {
14483                                    std::cmp::Ordering::Greater
14484                                } else {
14485                                    std::cmp::Ordering::Equal
14486                                }
14487                            })
14488                            .is_ok();
14489
14490                        if !overlaps {
14491                            next_selected_range = Some(offset_range);
14492                            break;
14493                        }
14494                    }
14495                }
14496
14497                if let Some(next_selected_range) = next_selected_range {
14498                    self.select_match_ranges(
14499                        next_selected_range,
14500                        last_selection.reversed,
14501                        replace_newest,
14502                        autoscroll,
14503                        window,
14504                        cx,
14505                    );
14506                } else {
14507                    select_next_state.done = true;
14508                }
14509            }
14510
14511            self.select_next_state = Some(select_next_state);
14512        } else {
14513            let mut only_carets = true;
14514            let mut same_text_selected = true;
14515            let mut selected_text = None;
14516
14517            let mut selections_iter = selections.iter().peekable();
14518            while let Some(selection) = selections_iter.next() {
14519                if selection.start != selection.end {
14520                    only_carets = false;
14521                }
14522
14523                if same_text_selected {
14524                    if selected_text.is_none() {
14525                        selected_text =
14526                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14527                    }
14528
14529                    if let Some(next_selection) = selections_iter.peek() {
14530                        if next_selection.range().len() == selection.range().len() {
14531                            let next_selected_text = buffer
14532                                .text_for_range(next_selection.range())
14533                                .collect::<String>();
14534                            if Some(next_selected_text) != selected_text {
14535                                same_text_selected = false;
14536                                selected_text = None;
14537                            }
14538                        } else {
14539                            same_text_selected = false;
14540                            selected_text = None;
14541                        }
14542                    }
14543                }
14544            }
14545
14546            if only_carets {
14547                for selection in &mut selections {
14548                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14549                    selection.start = word_range.start;
14550                    selection.end = word_range.end;
14551                    selection.goal = SelectionGoal::None;
14552                    selection.reversed = false;
14553                    self.select_match_ranges(
14554                        selection.start..selection.end,
14555                        selection.reversed,
14556                        replace_newest,
14557                        autoscroll,
14558                        window,
14559                        cx,
14560                    );
14561                }
14562
14563                if selections.len() == 1 {
14564                    let selection = selections
14565                        .last()
14566                        .expect("ensured that there's only one selection");
14567                    let query = buffer
14568                        .text_for_range(selection.start..selection.end)
14569                        .collect::<String>();
14570                    let is_empty = query.is_empty();
14571                    let select_state = SelectNextState {
14572                        query: AhoCorasick::new(&[query])?,
14573                        wordwise: true,
14574                        done: is_empty,
14575                    };
14576                    self.select_next_state = Some(select_state);
14577                } else {
14578                    self.select_next_state = None;
14579                }
14580            } else if let Some(selected_text) = selected_text {
14581                self.select_next_state = Some(SelectNextState {
14582                    query: AhoCorasick::new(&[selected_text])?,
14583                    wordwise: false,
14584                    done: false,
14585                });
14586                self.select_next_match_internal(
14587                    display_map,
14588                    replace_newest,
14589                    autoscroll,
14590                    window,
14591                    cx,
14592                )?;
14593            }
14594        }
14595        Ok(())
14596    }
14597
14598    pub fn select_all_matches(
14599        &mut self,
14600        _action: &SelectAllMatches,
14601        window: &mut Window,
14602        cx: &mut Context<Self>,
14603    ) -> Result<()> {
14604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14605
14606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14607
14608        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14609        let Some(select_next_state) = self.select_next_state.as_mut() else {
14610            return Ok(());
14611        };
14612        if select_next_state.done {
14613            return Ok(());
14614        }
14615
14616        let mut new_selections = Vec::new();
14617
14618        let reversed = self.selections.oldest::<usize>(cx).reversed;
14619        let buffer = display_map.buffer_snapshot();
14620        let query_matches = select_next_state
14621            .query
14622            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14623
14624        for query_match in query_matches.into_iter() {
14625            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14626            let offset_range = if reversed {
14627                query_match.end()..query_match.start()
14628            } else {
14629                query_match.start()..query_match.end()
14630            };
14631
14632            if !select_next_state.wordwise
14633                || (!buffer.is_inside_word(offset_range.start, None)
14634                    && !buffer.is_inside_word(offset_range.end, None))
14635            {
14636                new_selections.push(offset_range.start..offset_range.end);
14637            }
14638        }
14639
14640        select_next_state.done = true;
14641
14642        if new_selections.is_empty() {
14643            log::error!("bug: new_selections is empty in select_all_matches");
14644            return Ok(());
14645        }
14646
14647        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14648        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14649            selections.select_ranges(new_selections)
14650        });
14651
14652        Ok(())
14653    }
14654
14655    pub fn select_next(
14656        &mut self,
14657        action: &SelectNext,
14658        window: &mut Window,
14659        cx: &mut Context<Self>,
14660    ) -> Result<()> {
14661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14663        self.select_next_match_internal(
14664            &display_map,
14665            action.replace_newest,
14666            Some(Autoscroll::newest()),
14667            window,
14668            cx,
14669        )?;
14670        Ok(())
14671    }
14672
14673    pub fn select_previous(
14674        &mut self,
14675        action: &SelectPrevious,
14676        window: &mut Window,
14677        cx: &mut Context<Self>,
14678    ) -> Result<()> {
14679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14681        let buffer = display_map.buffer_snapshot();
14682        let mut selections = self.selections.all::<usize>(cx);
14683        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14684            let query = &select_prev_state.query;
14685            if !select_prev_state.done {
14686                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14687                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14688                let mut next_selected_range = None;
14689                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14690                let bytes_before_last_selection =
14691                    buffer.reversed_bytes_in_range(0..last_selection.start);
14692                let bytes_after_first_selection =
14693                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14694                let query_matches = query
14695                    .stream_find_iter(bytes_before_last_selection)
14696                    .map(|result| (last_selection.start, result))
14697                    .chain(
14698                        query
14699                            .stream_find_iter(bytes_after_first_selection)
14700                            .map(|result| (buffer.len(), result)),
14701                    );
14702                for (end_offset, query_match) in query_matches {
14703                    let query_match = query_match.unwrap(); // can only fail due to I/O
14704                    let offset_range =
14705                        end_offset - query_match.end()..end_offset - query_match.start();
14706
14707                    if !select_prev_state.wordwise
14708                        || (!buffer.is_inside_word(offset_range.start, None)
14709                            && !buffer.is_inside_word(offset_range.end, None))
14710                    {
14711                        next_selected_range = Some(offset_range);
14712                        break;
14713                    }
14714                }
14715
14716                if let Some(next_selected_range) = next_selected_range {
14717                    self.select_match_ranges(
14718                        next_selected_range,
14719                        last_selection.reversed,
14720                        action.replace_newest,
14721                        Some(Autoscroll::newest()),
14722                        window,
14723                        cx,
14724                    );
14725                } else {
14726                    select_prev_state.done = true;
14727                }
14728            }
14729
14730            self.select_prev_state = Some(select_prev_state);
14731        } else {
14732            let mut only_carets = true;
14733            let mut same_text_selected = true;
14734            let mut selected_text = None;
14735
14736            let mut selections_iter = selections.iter().peekable();
14737            while let Some(selection) = selections_iter.next() {
14738                if selection.start != selection.end {
14739                    only_carets = false;
14740                }
14741
14742                if same_text_selected {
14743                    if selected_text.is_none() {
14744                        selected_text =
14745                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14746                    }
14747
14748                    if let Some(next_selection) = selections_iter.peek() {
14749                        if next_selection.range().len() == selection.range().len() {
14750                            let next_selected_text = buffer
14751                                .text_for_range(next_selection.range())
14752                                .collect::<String>();
14753                            if Some(next_selected_text) != selected_text {
14754                                same_text_selected = false;
14755                                selected_text = None;
14756                            }
14757                        } else {
14758                            same_text_selected = false;
14759                            selected_text = None;
14760                        }
14761                    }
14762                }
14763            }
14764
14765            if only_carets {
14766                for selection in &mut selections {
14767                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14768                    selection.start = word_range.start;
14769                    selection.end = word_range.end;
14770                    selection.goal = SelectionGoal::None;
14771                    selection.reversed = false;
14772                    self.select_match_ranges(
14773                        selection.start..selection.end,
14774                        selection.reversed,
14775                        action.replace_newest,
14776                        Some(Autoscroll::newest()),
14777                        window,
14778                        cx,
14779                    );
14780                }
14781                if selections.len() == 1 {
14782                    let selection = selections
14783                        .last()
14784                        .expect("ensured that there's only one selection");
14785                    let query = buffer
14786                        .text_for_range(selection.start..selection.end)
14787                        .collect::<String>();
14788                    let is_empty = query.is_empty();
14789                    let select_state = SelectNextState {
14790                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14791                        wordwise: true,
14792                        done: is_empty,
14793                    };
14794                    self.select_prev_state = Some(select_state);
14795                } else {
14796                    self.select_prev_state = None;
14797                }
14798            } else if let Some(selected_text) = selected_text {
14799                self.select_prev_state = Some(SelectNextState {
14800                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14801                    wordwise: false,
14802                    done: false,
14803                });
14804                self.select_previous(action, window, cx)?;
14805            }
14806        }
14807        Ok(())
14808    }
14809
14810    pub fn find_next_match(
14811        &mut self,
14812        _: &FindNextMatch,
14813        window: &mut Window,
14814        cx: &mut Context<Self>,
14815    ) -> Result<()> {
14816        let selections = self.selections.disjoint_anchors_arc();
14817        match selections.first() {
14818            Some(first) if selections.len() >= 2 => {
14819                self.change_selections(Default::default(), window, cx, |s| {
14820                    s.select_ranges([first.range()]);
14821                });
14822            }
14823            _ => self.select_next(
14824                &SelectNext {
14825                    replace_newest: true,
14826                },
14827                window,
14828                cx,
14829            )?,
14830        }
14831        Ok(())
14832    }
14833
14834    pub fn find_previous_match(
14835        &mut self,
14836        _: &FindPreviousMatch,
14837        window: &mut Window,
14838        cx: &mut Context<Self>,
14839    ) -> Result<()> {
14840        let selections = self.selections.disjoint_anchors_arc();
14841        match selections.last() {
14842            Some(last) if selections.len() >= 2 => {
14843                self.change_selections(Default::default(), window, cx, |s| {
14844                    s.select_ranges([last.range()]);
14845                });
14846            }
14847            _ => self.select_previous(
14848                &SelectPrevious {
14849                    replace_newest: true,
14850                },
14851                window,
14852                cx,
14853            )?,
14854        }
14855        Ok(())
14856    }
14857
14858    pub fn toggle_comments(
14859        &mut self,
14860        action: &ToggleComments,
14861        window: &mut Window,
14862        cx: &mut Context<Self>,
14863    ) {
14864        if self.read_only(cx) {
14865            return;
14866        }
14867        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14868        let text_layout_details = &self.text_layout_details(window);
14869        self.transact(window, cx, |this, window, cx| {
14870            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14871            let mut edits = Vec::new();
14872            let mut selection_edit_ranges = Vec::new();
14873            let mut last_toggled_row = None;
14874            let snapshot = this.buffer.read(cx).read(cx);
14875            let empty_str: Arc<str> = Arc::default();
14876            let mut suffixes_inserted = Vec::new();
14877            let ignore_indent = action.ignore_indent;
14878
14879            fn comment_prefix_range(
14880                snapshot: &MultiBufferSnapshot,
14881                row: MultiBufferRow,
14882                comment_prefix: &str,
14883                comment_prefix_whitespace: &str,
14884                ignore_indent: bool,
14885            ) -> Range<Point> {
14886                let indent_size = if ignore_indent {
14887                    0
14888                } else {
14889                    snapshot.indent_size_for_line(row).len
14890                };
14891
14892                let start = Point::new(row.0, indent_size);
14893
14894                let mut line_bytes = snapshot
14895                    .bytes_in_range(start..snapshot.max_point())
14896                    .flatten()
14897                    .copied();
14898
14899                // If this line currently begins with the line comment prefix, then record
14900                // the range containing the prefix.
14901                if line_bytes
14902                    .by_ref()
14903                    .take(comment_prefix.len())
14904                    .eq(comment_prefix.bytes())
14905                {
14906                    // Include any whitespace that matches the comment prefix.
14907                    let matching_whitespace_len = line_bytes
14908                        .zip(comment_prefix_whitespace.bytes())
14909                        .take_while(|(a, b)| a == b)
14910                        .count() as u32;
14911                    let end = Point::new(
14912                        start.row,
14913                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14914                    );
14915                    start..end
14916                } else {
14917                    start..start
14918                }
14919            }
14920
14921            fn comment_suffix_range(
14922                snapshot: &MultiBufferSnapshot,
14923                row: MultiBufferRow,
14924                comment_suffix: &str,
14925                comment_suffix_has_leading_space: bool,
14926            ) -> Range<Point> {
14927                let end = Point::new(row.0, snapshot.line_len(row));
14928                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14929
14930                let mut line_end_bytes = snapshot
14931                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14932                    .flatten()
14933                    .copied();
14934
14935                let leading_space_len = if suffix_start_column > 0
14936                    && line_end_bytes.next() == Some(b' ')
14937                    && comment_suffix_has_leading_space
14938                {
14939                    1
14940                } else {
14941                    0
14942                };
14943
14944                // If this line currently begins with the line comment prefix, then record
14945                // the range containing the prefix.
14946                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14947                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14948                    start..end
14949                } else {
14950                    end..end
14951                }
14952            }
14953
14954            // TODO: Handle selections that cross excerpts
14955            for selection in &mut selections {
14956                let start_column = snapshot
14957                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14958                    .len;
14959                let language = if let Some(language) =
14960                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14961                {
14962                    language
14963                } else {
14964                    continue;
14965                };
14966
14967                selection_edit_ranges.clear();
14968
14969                // If multiple selections contain a given row, avoid processing that
14970                // row more than once.
14971                let mut start_row = MultiBufferRow(selection.start.row);
14972                if last_toggled_row == Some(start_row) {
14973                    start_row = start_row.next_row();
14974                }
14975                let end_row =
14976                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14977                        MultiBufferRow(selection.end.row - 1)
14978                    } else {
14979                        MultiBufferRow(selection.end.row)
14980                    };
14981                last_toggled_row = Some(end_row);
14982
14983                if start_row > end_row {
14984                    continue;
14985                }
14986
14987                // If the language has line comments, toggle those.
14988                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14989
14990                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14991                if ignore_indent {
14992                    full_comment_prefixes = full_comment_prefixes
14993                        .into_iter()
14994                        .map(|s| Arc::from(s.trim_end()))
14995                        .collect();
14996                }
14997
14998                if !full_comment_prefixes.is_empty() {
14999                    let first_prefix = full_comment_prefixes
15000                        .first()
15001                        .expect("prefixes is non-empty");
15002                    let prefix_trimmed_lengths = full_comment_prefixes
15003                        .iter()
15004                        .map(|p| p.trim_end_matches(' ').len())
15005                        .collect::<SmallVec<[usize; 4]>>();
15006
15007                    let mut all_selection_lines_are_comments = true;
15008
15009                    for row in start_row.0..=end_row.0 {
15010                        let row = MultiBufferRow(row);
15011                        if start_row < end_row && snapshot.is_line_blank(row) {
15012                            continue;
15013                        }
15014
15015                        let prefix_range = full_comment_prefixes
15016                            .iter()
15017                            .zip(prefix_trimmed_lengths.iter().copied())
15018                            .map(|(prefix, trimmed_prefix_len)| {
15019                                comment_prefix_range(
15020                                    snapshot.deref(),
15021                                    row,
15022                                    &prefix[..trimmed_prefix_len],
15023                                    &prefix[trimmed_prefix_len..],
15024                                    ignore_indent,
15025                                )
15026                            })
15027                            .max_by_key(|range| range.end.column - range.start.column)
15028                            .expect("prefixes is non-empty");
15029
15030                        if prefix_range.is_empty() {
15031                            all_selection_lines_are_comments = false;
15032                        }
15033
15034                        selection_edit_ranges.push(prefix_range);
15035                    }
15036
15037                    if all_selection_lines_are_comments {
15038                        edits.extend(
15039                            selection_edit_ranges
15040                                .iter()
15041                                .cloned()
15042                                .map(|range| (range, empty_str.clone())),
15043                        );
15044                    } else {
15045                        let min_column = selection_edit_ranges
15046                            .iter()
15047                            .map(|range| range.start.column)
15048                            .min()
15049                            .unwrap_or(0);
15050                        edits.extend(selection_edit_ranges.iter().map(|range| {
15051                            let position = Point::new(range.start.row, min_column);
15052                            (position..position, first_prefix.clone())
15053                        }));
15054                    }
15055                } else if let Some(BlockCommentConfig {
15056                    start: full_comment_prefix,
15057                    end: comment_suffix,
15058                    ..
15059                }) = language.block_comment()
15060                {
15061                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15062                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15063                    let prefix_range = comment_prefix_range(
15064                        snapshot.deref(),
15065                        start_row,
15066                        comment_prefix,
15067                        comment_prefix_whitespace,
15068                        ignore_indent,
15069                    );
15070                    let suffix_range = comment_suffix_range(
15071                        snapshot.deref(),
15072                        end_row,
15073                        comment_suffix.trim_start_matches(' '),
15074                        comment_suffix.starts_with(' '),
15075                    );
15076
15077                    if prefix_range.is_empty() || suffix_range.is_empty() {
15078                        edits.push((
15079                            prefix_range.start..prefix_range.start,
15080                            full_comment_prefix.clone(),
15081                        ));
15082                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15083                        suffixes_inserted.push((end_row, comment_suffix.len()));
15084                    } else {
15085                        edits.push((prefix_range, empty_str.clone()));
15086                        edits.push((suffix_range, empty_str.clone()));
15087                    }
15088                } else {
15089                    continue;
15090                }
15091            }
15092
15093            drop(snapshot);
15094            this.buffer.update(cx, |buffer, cx| {
15095                buffer.edit(edits, None, cx);
15096            });
15097
15098            // Adjust selections so that they end before any comment suffixes that
15099            // were inserted.
15100            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15101            let mut selections = this.selections.all::<Point>(cx);
15102            let snapshot = this.buffer.read(cx).read(cx);
15103            for selection in &mut selections {
15104                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15105                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15106                        Ordering::Less => {
15107                            suffixes_inserted.next();
15108                            continue;
15109                        }
15110                        Ordering::Greater => break,
15111                        Ordering::Equal => {
15112                            if selection.end.column == snapshot.line_len(row) {
15113                                if selection.is_empty() {
15114                                    selection.start.column -= suffix_len as u32;
15115                                }
15116                                selection.end.column -= suffix_len as u32;
15117                            }
15118                            break;
15119                        }
15120                    }
15121                }
15122            }
15123
15124            drop(snapshot);
15125            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15126
15127            let selections = this.selections.all::<Point>(cx);
15128            let selections_on_single_row = selections.windows(2).all(|selections| {
15129                selections[0].start.row == selections[1].start.row
15130                    && selections[0].end.row == selections[1].end.row
15131                    && selections[0].start.row == selections[0].end.row
15132            });
15133            let selections_selecting = selections
15134                .iter()
15135                .any(|selection| selection.start != selection.end);
15136            let advance_downwards = action.advance_downwards
15137                && selections_on_single_row
15138                && !selections_selecting
15139                && !matches!(this.mode, EditorMode::SingleLine);
15140
15141            if advance_downwards {
15142                let snapshot = this.buffer.read(cx).snapshot(cx);
15143
15144                this.change_selections(Default::default(), window, cx, |s| {
15145                    s.move_cursors_with(|display_snapshot, display_point, _| {
15146                        let mut point = display_point.to_point(display_snapshot);
15147                        point.row += 1;
15148                        point = snapshot.clip_point(point, Bias::Left);
15149                        let display_point = point.to_display_point(display_snapshot);
15150                        let goal = SelectionGoal::HorizontalPosition(
15151                            display_snapshot
15152                                .x_for_display_point(display_point, text_layout_details)
15153                                .into(),
15154                        );
15155                        (display_point, goal)
15156                    })
15157                });
15158            }
15159        });
15160    }
15161
15162    pub fn select_enclosing_symbol(
15163        &mut self,
15164        _: &SelectEnclosingSymbol,
15165        window: &mut Window,
15166        cx: &mut Context<Self>,
15167    ) {
15168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15169
15170        let buffer = self.buffer.read(cx).snapshot(cx);
15171        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15172
15173        fn update_selection(
15174            selection: &Selection<usize>,
15175            buffer_snap: &MultiBufferSnapshot,
15176        ) -> Option<Selection<usize>> {
15177            let cursor = selection.head();
15178            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15179            for symbol in symbols.iter().rev() {
15180                let start = symbol.range.start.to_offset(buffer_snap);
15181                let end = symbol.range.end.to_offset(buffer_snap);
15182                let new_range = start..end;
15183                if start < selection.start || end > selection.end {
15184                    return Some(Selection {
15185                        id: selection.id,
15186                        start: new_range.start,
15187                        end: new_range.end,
15188                        goal: SelectionGoal::None,
15189                        reversed: selection.reversed,
15190                    });
15191                }
15192            }
15193            None
15194        }
15195
15196        let mut selected_larger_symbol = false;
15197        let new_selections = old_selections
15198            .iter()
15199            .map(|selection| match update_selection(selection, &buffer) {
15200                Some(new_selection) => {
15201                    if new_selection.range() != selection.range() {
15202                        selected_larger_symbol = true;
15203                    }
15204                    new_selection
15205                }
15206                None => selection.clone(),
15207            })
15208            .collect::<Vec<_>>();
15209
15210        if selected_larger_symbol {
15211            self.change_selections(Default::default(), window, cx, |s| {
15212                s.select(new_selections);
15213            });
15214        }
15215    }
15216
15217    pub fn select_larger_syntax_node(
15218        &mut self,
15219        _: &SelectLargerSyntaxNode,
15220        window: &mut Window,
15221        cx: &mut Context<Self>,
15222    ) {
15223        let Some(visible_row_count) = self.visible_row_count() else {
15224            return;
15225        };
15226        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15227        if old_selections.is_empty() {
15228            return;
15229        }
15230
15231        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15232
15233        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15234        let buffer = self.buffer.read(cx).snapshot(cx);
15235
15236        let mut selected_larger_node = false;
15237        let mut new_selections = old_selections
15238            .iter()
15239            .map(|selection| {
15240                let old_range = selection.start..selection.end;
15241
15242                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15243                    // manually select word at selection
15244                    if ["string_content", "inline"].contains(&node.kind()) {
15245                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15246                        // ignore if word is already selected
15247                        if !word_range.is_empty() && old_range != word_range {
15248                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15249                            // only select word if start and end point belongs to same word
15250                            if word_range == last_word_range {
15251                                selected_larger_node = true;
15252                                return Selection {
15253                                    id: selection.id,
15254                                    start: word_range.start,
15255                                    end: word_range.end,
15256                                    goal: SelectionGoal::None,
15257                                    reversed: selection.reversed,
15258                                };
15259                            }
15260                        }
15261                    }
15262                }
15263
15264                let mut new_range = old_range.clone();
15265                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15266                    new_range = range;
15267                    if !node.is_named() {
15268                        continue;
15269                    }
15270                    if !display_map.intersects_fold(new_range.start)
15271                        && !display_map.intersects_fold(new_range.end)
15272                    {
15273                        break;
15274                    }
15275                }
15276
15277                selected_larger_node |= new_range != old_range;
15278                Selection {
15279                    id: selection.id,
15280                    start: new_range.start,
15281                    end: new_range.end,
15282                    goal: SelectionGoal::None,
15283                    reversed: selection.reversed,
15284                }
15285            })
15286            .collect::<Vec<_>>();
15287
15288        if !selected_larger_node {
15289            return; // don't put this call in the history
15290        }
15291
15292        // scroll based on transformation done to the last selection created by the user
15293        let (last_old, last_new) = old_selections
15294            .last()
15295            .zip(new_selections.last().cloned())
15296            .expect("old_selections isn't empty");
15297
15298        // revert selection
15299        let is_selection_reversed = {
15300            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15301            new_selections.last_mut().expect("checked above").reversed =
15302                should_newest_selection_be_reversed;
15303            should_newest_selection_be_reversed
15304        };
15305
15306        if selected_larger_node {
15307            self.select_syntax_node_history.disable_clearing = true;
15308            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15309                s.select(new_selections.clone());
15310            });
15311            self.select_syntax_node_history.disable_clearing = false;
15312        }
15313
15314        let start_row = last_new.start.to_display_point(&display_map).row().0;
15315        let end_row = last_new.end.to_display_point(&display_map).row().0;
15316        let selection_height = end_row - start_row + 1;
15317        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15318
15319        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15320        let scroll_behavior = if fits_on_the_screen {
15321            self.request_autoscroll(Autoscroll::fit(), cx);
15322            SelectSyntaxNodeScrollBehavior::FitSelection
15323        } else if is_selection_reversed {
15324            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15325            SelectSyntaxNodeScrollBehavior::CursorTop
15326        } else {
15327            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15328            SelectSyntaxNodeScrollBehavior::CursorBottom
15329        };
15330
15331        self.select_syntax_node_history.push((
15332            old_selections,
15333            scroll_behavior,
15334            is_selection_reversed,
15335        ));
15336    }
15337
15338    pub fn select_smaller_syntax_node(
15339        &mut self,
15340        _: &SelectSmallerSyntaxNode,
15341        window: &mut Window,
15342        cx: &mut Context<Self>,
15343    ) {
15344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15345
15346        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15347            self.select_syntax_node_history.pop()
15348        {
15349            if let Some(selection) = selections.last_mut() {
15350                selection.reversed = is_selection_reversed;
15351            }
15352
15353            self.select_syntax_node_history.disable_clearing = true;
15354            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15355                s.select(selections.to_vec());
15356            });
15357            self.select_syntax_node_history.disable_clearing = false;
15358
15359            match scroll_behavior {
15360                SelectSyntaxNodeScrollBehavior::CursorTop => {
15361                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15362                }
15363                SelectSyntaxNodeScrollBehavior::FitSelection => {
15364                    self.request_autoscroll(Autoscroll::fit(), cx);
15365                }
15366                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15367                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15368                }
15369            }
15370        }
15371    }
15372
15373    pub fn unwrap_syntax_node(
15374        &mut self,
15375        _: &UnwrapSyntaxNode,
15376        window: &mut Window,
15377        cx: &mut Context<Self>,
15378    ) {
15379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15380
15381        let buffer = self.buffer.read(cx).snapshot(cx);
15382        let selections = self
15383            .selections
15384            .all::<usize>(cx)
15385            .into_iter()
15386            // subtracting the offset requires sorting
15387            .sorted_by_key(|i| i.start);
15388
15389        let full_edits = selections
15390            .into_iter()
15391            .filter_map(|selection| {
15392                let child = if selection.is_empty()
15393                    && let Some((_, ancestor_range)) =
15394                        buffer.syntax_ancestor(selection.start..selection.end)
15395                {
15396                    ancestor_range
15397                } else {
15398                    selection.range()
15399                };
15400
15401                let mut parent = child.clone();
15402                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15403                    parent = ancestor_range;
15404                    if parent.start < child.start || parent.end > child.end {
15405                        break;
15406                    }
15407                }
15408
15409                if parent == child {
15410                    return None;
15411                }
15412                let text = buffer.text_for_range(child).collect::<String>();
15413                Some((selection.id, parent, text))
15414            })
15415            .collect::<Vec<_>>();
15416        if full_edits.is_empty() {
15417            return;
15418        }
15419
15420        self.transact(window, cx, |this, window, cx| {
15421            this.buffer.update(cx, |buffer, cx| {
15422                buffer.edit(
15423                    full_edits
15424                        .iter()
15425                        .map(|(_, p, t)| (p.clone(), t.clone()))
15426                        .collect::<Vec<_>>(),
15427                    None,
15428                    cx,
15429                );
15430            });
15431            this.change_selections(Default::default(), window, cx, |s| {
15432                let mut offset = 0;
15433                let mut selections = vec![];
15434                for (id, parent, text) in full_edits {
15435                    let start = parent.start - offset;
15436                    offset += parent.len() - text.len();
15437                    selections.push(Selection {
15438                        id,
15439                        start,
15440                        end: start + text.len(),
15441                        reversed: false,
15442                        goal: Default::default(),
15443                    });
15444                }
15445                s.select(selections);
15446            });
15447        });
15448    }
15449
15450    pub fn select_next_syntax_node(
15451        &mut self,
15452        _: &SelectNextSyntaxNode,
15453        window: &mut Window,
15454        cx: &mut Context<Self>,
15455    ) {
15456        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15457        if old_selections.is_empty() {
15458            return;
15459        }
15460
15461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15462
15463        let buffer = self.buffer.read(cx).snapshot(cx);
15464        let mut selected_sibling = false;
15465
15466        let new_selections = old_selections
15467            .iter()
15468            .map(|selection| {
15469                let old_range = selection.start..selection.end;
15470
15471                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15472                    let new_range = node.byte_range();
15473                    selected_sibling = true;
15474                    Selection {
15475                        id: selection.id,
15476                        start: new_range.start,
15477                        end: new_range.end,
15478                        goal: SelectionGoal::None,
15479                        reversed: selection.reversed,
15480                    }
15481                } else {
15482                    selection.clone()
15483                }
15484            })
15485            .collect::<Vec<_>>();
15486
15487        if selected_sibling {
15488            self.change_selections(
15489                SelectionEffects::scroll(Autoscroll::fit()),
15490                window,
15491                cx,
15492                |s| {
15493                    s.select(new_selections);
15494                },
15495            );
15496        }
15497    }
15498
15499    pub fn select_prev_syntax_node(
15500        &mut self,
15501        _: &SelectPreviousSyntaxNode,
15502        window: &mut Window,
15503        cx: &mut Context<Self>,
15504    ) {
15505        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15506        if old_selections.is_empty() {
15507            return;
15508        }
15509
15510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15511
15512        let buffer = self.buffer.read(cx).snapshot(cx);
15513        let mut selected_sibling = false;
15514
15515        let new_selections = old_selections
15516            .iter()
15517            .map(|selection| {
15518                let old_range = selection.start..selection.end;
15519
15520                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15521                    let new_range = node.byte_range();
15522                    selected_sibling = true;
15523                    Selection {
15524                        id: selection.id,
15525                        start: new_range.start,
15526                        end: new_range.end,
15527                        goal: SelectionGoal::None,
15528                        reversed: selection.reversed,
15529                    }
15530                } else {
15531                    selection.clone()
15532                }
15533            })
15534            .collect::<Vec<_>>();
15535
15536        if selected_sibling {
15537            self.change_selections(
15538                SelectionEffects::scroll(Autoscroll::fit()),
15539                window,
15540                cx,
15541                |s| {
15542                    s.select(new_selections);
15543                },
15544            );
15545        }
15546    }
15547
15548    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15549        if !EditorSettings::get_global(cx).gutter.runnables {
15550            self.clear_tasks();
15551            return Task::ready(());
15552        }
15553        let project = self.project().map(Entity::downgrade);
15554        let task_sources = self.lsp_task_sources(cx);
15555        let multi_buffer = self.buffer.downgrade();
15556        cx.spawn_in(window, async move |editor, cx| {
15557            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15558            let Some(project) = project.and_then(|p| p.upgrade()) else {
15559                return;
15560            };
15561            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15562                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15563            }) else {
15564                return;
15565            };
15566
15567            let hide_runnables = project
15568                .update(cx, |project, _| project.is_via_collab())
15569                .unwrap_or(true);
15570            if hide_runnables {
15571                return;
15572            }
15573            let new_rows =
15574                cx.background_spawn({
15575                    let snapshot = display_snapshot.clone();
15576                    async move {
15577                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15578                    }
15579                })
15580                    .await;
15581            let Ok(lsp_tasks) =
15582                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15583            else {
15584                return;
15585            };
15586            let lsp_tasks = lsp_tasks.await;
15587
15588            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15589                lsp_tasks
15590                    .into_iter()
15591                    .flat_map(|(kind, tasks)| {
15592                        tasks.into_iter().filter_map(move |(location, task)| {
15593                            Some((kind.clone(), location?, task))
15594                        })
15595                    })
15596                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15597                        let buffer = location.target.buffer;
15598                        let buffer_snapshot = buffer.read(cx).snapshot();
15599                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15600                            |(excerpt_id, snapshot, _)| {
15601                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15602                                    display_snapshot
15603                                        .buffer_snapshot()
15604                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15605                                } else {
15606                                    None
15607                                }
15608                            },
15609                        );
15610                        if let Some(offset) = offset {
15611                            let task_buffer_range =
15612                                location.target.range.to_point(&buffer_snapshot);
15613                            let context_buffer_range =
15614                                task_buffer_range.to_offset(&buffer_snapshot);
15615                            let context_range = BufferOffset(context_buffer_range.start)
15616                                ..BufferOffset(context_buffer_range.end);
15617
15618                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15619                                .or_insert_with(|| RunnableTasks {
15620                                    templates: Vec::new(),
15621                                    offset,
15622                                    column: task_buffer_range.start.column,
15623                                    extra_variables: HashMap::default(),
15624                                    context_range,
15625                                })
15626                                .templates
15627                                .push((kind, task.original_task().clone()));
15628                        }
15629
15630                        acc
15631                    })
15632            }) else {
15633                return;
15634            };
15635
15636            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15637                buffer.language_settings(cx).tasks.prefer_lsp
15638            }) else {
15639                return;
15640            };
15641
15642            let rows = Self::runnable_rows(
15643                project,
15644                display_snapshot,
15645                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15646                new_rows,
15647                cx.clone(),
15648            )
15649            .await;
15650            editor
15651                .update(cx, |editor, _| {
15652                    editor.clear_tasks();
15653                    for (key, mut value) in rows {
15654                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15655                            value.templates.extend(lsp_tasks.templates);
15656                        }
15657
15658                        editor.insert_tasks(key, value);
15659                    }
15660                    for (key, value) in lsp_tasks_by_rows {
15661                        editor.insert_tasks(key, value);
15662                    }
15663                })
15664                .ok();
15665        })
15666    }
15667    fn fetch_runnable_ranges(
15668        snapshot: &DisplaySnapshot,
15669        range: Range<Anchor>,
15670    ) -> Vec<language::RunnableRange> {
15671        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15672    }
15673
15674    fn runnable_rows(
15675        project: Entity<Project>,
15676        snapshot: DisplaySnapshot,
15677        prefer_lsp: bool,
15678        runnable_ranges: Vec<RunnableRange>,
15679        cx: AsyncWindowContext,
15680    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15681        cx.spawn(async move |cx| {
15682            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15683            for mut runnable in runnable_ranges {
15684                let Some(tasks) = cx
15685                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15686                    .ok()
15687                else {
15688                    continue;
15689                };
15690                let mut tasks = tasks.await;
15691
15692                if prefer_lsp {
15693                    tasks.retain(|(task_kind, _)| {
15694                        !matches!(task_kind, TaskSourceKind::Language { .. })
15695                    });
15696                }
15697                if tasks.is_empty() {
15698                    continue;
15699                }
15700
15701                let point = runnable
15702                    .run_range
15703                    .start
15704                    .to_point(&snapshot.buffer_snapshot());
15705                let Some(row) = snapshot
15706                    .buffer_snapshot()
15707                    .buffer_line_for_row(MultiBufferRow(point.row))
15708                    .map(|(_, range)| range.start.row)
15709                else {
15710                    continue;
15711                };
15712
15713                let context_range =
15714                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15715                runnable_rows.push((
15716                    (runnable.buffer_id, row),
15717                    RunnableTasks {
15718                        templates: tasks,
15719                        offset: snapshot
15720                            .buffer_snapshot()
15721                            .anchor_before(runnable.run_range.start),
15722                        context_range,
15723                        column: point.column,
15724                        extra_variables: runnable.extra_captures,
15725                    },
15726                ));
15727            }
15728            runnable_rows
15729        })
15730    }
15731
15732    fn templates_with_tags(
15733        project: &Entity<Project>,
15734        runnable: &mut Runnable,
15735        cx: &mut App,
15736    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15737        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15738            let (worktree_id, file) = project
15739                .buffer_for_id(runnable.buffer, cx)
15740                .and_then(|buffer| buffer.read(cx).file())
15741                .map(|file| (file.worktree_id(cx), file.clone()))
15742                .unzip();
15743
15744            (
15745                project.task_store().read(cx).task_inventory().cloned(),
15746                worktree_id,
15747                file,
15748            )
15749        });
15750
15751        let tags = mem::take(&mut runnable.tags);
15752        let language = runnable.language.clone();
15753        cx.spawn(async move |cx| {
15754            let mut templates_with_tags = Vec::new();
15755            if let Some(inventory) = inventory {
15756                for RunnableTag(tag) in tags {
15757                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15758                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15759                    }) else {
15760                        return templates_with_tags;
15761                    };
15762                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15763                        move |(_, template)| {
15764                            template.tags.iter().any(|source_tag| source_tag == &tag)
15765                        },
15766                    ));
15767                }
15768            }
15769            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15770
15771            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15772                // Strongest source wins; if we have worktree tag binding, prefer that to
15773                // global and language bindings;
15774                // if we have a global binding, prefer that to language binding.
15775                let first_mismatch = templates_with_tags
15776                    .iter()
15777                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15778                if let Some(index) = first_mismatch {
15779                    templates_with_tags.truncate(index);
15780                }
15781            }
15782
15783            templates_with_tags
15784        })
15785    }
15786
15787    pub fn move_to_enclosing_bracket(
15788        &mut self,
15789        _: &MoveToEnclosingBracket,
15790        window: &mut Window,
15791        cx: &mut Context<Self>,
15792    ) {
15793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15794        self.change_selections(Default::default(), window, cx, |s| {
15795            s.move_offsets_with(|snapshot, selection| {
15796                let Some(enclosing_bracket_ranges) =
15797                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15798                else {
15799                    return;
15800                };
15801
15802                let mut best_length = usize::MAX;
15803                let mut best_inside = false;
15804                let mut best_in_bracket_range = false;
15805                let mut best_destination = None;
15806                for (open, close) in enclosing_bracket_ranges {
15807                    let close = close.to_inclusive();
15808                    let length = close.end() - open.start;
15809                    let inside = selection.start >= open.end && selection.end <= *close.start();
15810                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15811                        || close.contains(&selection.head());
15812
15813                    // If best is next to a bracket and current isn't, skip
15814                    if !in_bracket_range && best_in_bracket_range {
15815                        continue;
15816                    }
15817
15818                    // Prefer smaller lengths unless best is inside and current isn't
15819                    if length > best_length && (best_inside || !inside) {
15820                        continue;
15821                    }
15822
15823                    best_length = length;
15824                    best_inside = inside;
15825                    best_in_bracket_range = in_bracket_range;
15826                    best_destination = Some(
15827                        if close.contains(&selection.start) && close.contains(&selection.end) {
15828                            if inside { open.end } else { open.start }
15829                        } else if inside {
15830                            *close.start()
15831                        } else {
15832                            *close.end()
15833                        },
15834                    );
15835                }
15836
15837                if let Some(destination) = best_destination {
15838                    selection.collapse_to(destination, SelectionGoal::None);
15839                }
15840            })
15841        });
15842    }
15843
15844    pub fn undo_selection(
15845        &mut self,
15846        _: &UndoSelection,
15847        window: &mut Window,
15848        cx: &mut Context<Self>,
15849    ) {
15850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15851        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15852            self.selection_history.mode = SelectionHistoryMode::Undoing;
15853            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15854                this.end_selection(window, cx);
15855                this.change_selections(
15856                    SelectionEffects::scroll(Autoscroll::newest()),
15857                    window,
15858                    cx,
15859                    |s| s.select_anchors(entry.selections.to_vec()),
15860                );
15861            });
15862            self.selection_history.mode = SelectionHistoryMode::Normal;
15863
15864            self.select_next_state = entry.select_next_state;
15865            self.select_prev_state = entry.select_prev_state;
15866            self.add_selections_state = entry.add_selections_state;
15867        }
15868    }
15869
15870    pub fn redo_selection(
15871        &mut self,
15872        _: &RedoSelection,
15873        window: &mut Window,
15874        cx: &mut Context<Self>,
15875    ) {
15876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15877        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15878            self.selection_history.mode = SelectionHistoryMode::Redoing;
15879            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15880                this.end_selection(window, cx);
15881                this.change_selections(
15882                    SelectionEffects::scroll(Autoscroll::newest()),
15883                    window,
15884                    cx,
15885                    |s| s.select_anchors(entry.selections.to_vec()),
15886                );
15887            });
15888            self.selection_history.mode = SelectionHistoryMode::Normal;
15889
15890            self.select_next_state = entry.select_next_state;
15891            self.select_prev_state = entry.select_prev_state;
15892            self.add_selections_state = entry.add_selections_state;
15893        }
15894    }
15895
15896    pub fn expand_excerpts(
15897        &mut self,
15898        action: &ExpandExcerpts,
15899        _: &mut Window,
15900        cx: &mut Context<Self>,
15901    ) {
15902        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15903    }
15904
15905    pub fn expand_excerpts_down(
15906        &mut self,
15907        action: &ExpandExcerptsDown,
15908        _: &mut Window,
15909        cx: &mut Context<Self>,
15910    ) {
15911        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15912    }
15913
15914    pub fn expand_excerpts_up(
15915        &mut self,
15916        action: &ExpandExcerptsUp,
15917        _: &mut Window,
15918        cx: &mut Context<Self>,
15919    ) {
15920        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15921    }
15922
15923    pub fn expand_excerpts_for_direction(
15924        &mut self,
15925        lines: u32,
15926        direction: ExpandExcerptDirection,
15927
15928        cx: &mut Context<Self>,
15929    ) {
15930        let selections = self.selections.disjoint_anchors_arc();
15931
15932        let lines = if lines == 0 {
15933            EditorSettings::get_global(cx).expand_excerpt_lines
15934        } else {
15935            lines
15936        };
15937
15938        self.buffer.update(cx, |buffer, cx| {
15939            let snapshot = buffer.snapshot(cx);
15940            let mut excerpt_ids = selections
15941                .iter()
15942                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15943                .collect::<Vec<_>>();
15944            excerpt_ids.sort();
15945            excerpt_ids.dedup();
15946            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15947        })
15948    }
15949
15950    pub fn expand_excerpt(
15951        &mut self,
15952        excerpt: ExcerptId,
15953        direction: ExpandExcerptDirection,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        let current_scroll_position = self.scroll_position(cx);
15958        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15959        let mut should_scroll_up = false;
15960
15961        if direction == ExpandExcerptDirection::Down {
15962            let multi_buffer = self.buffer.read(cx);
15963            let snapshot = multi_buffer.snapshot(cx);
15964            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15965                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15966                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15967            {
15968                let buffer_snapshot = buffer.read(cx).snapshot();
15969                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15970                let last_row = buffer_snapshot.max_point().row;
15971                let lines_below = last_row.saturating_sub(excerpt_end_row);
15972                should_scroll_up = lines_below >= lines_to_expand;
15973            }
15974        }
15975
15976        self.buffer.update(cx, |buffer, cx| {
15977            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15978        });
15979
15980        if should_scroll_up {
15981            let new_scroll_position =
15982                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15983            self.set_scroll_position(new_scroll_position, window, cx);
15984        }
15985    }
15986
15987    pub fn go_to_singleton_buffer_point(
15988        &mut self,
15989        point: Point,
15990        window: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        self.go_to_singleton_buffer_range(point..point, window, cx);
15994    }
15995
15996    pub fn go_to_singleton_buffer_range(
15997        &mut self,
15998        range: Range<Point>,
15999        window: &mut Window,
16000        cx: &mut Context<Self>,
16001    ) {
16002        let multibuffer = self.buffer().read(cx);
16003        let Some(buffer) = multibuffer.as_singleton() else {
16004            return;
16005        };
16006        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16007            return;
16008        };
16009        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16010            return;
16011        };
16012        self.change_selections(
16013            SelectionEffects::default().nav_history(true),
16014            window,
16015            cx,
16016            |s| s.select_anchor_ranges([start..end]),
16017        );
16018    }
16019
16020    pub fn go_to_diagnostic(
16021        &mut self,
16022        action: &GoToDiagnostic,
16023        window: &mut Window,
16024        cx: &mut Context<Self>,
16025    ) {
16026        if !self.diagnostics_enabled() {
16027            return;
16028        }
16029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16030        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16031    }
16032
16033    pub fn go_to_prev_diagnostic(
16034        &mut self,
16035        action: &GoToPreviousDiagnostic,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        if !self.diagnostics_enabled() {
16040            return;
16041        }
16042        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16043        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16044    }
16045
16046    pub fn go_to_diagnostic_impl(
16047        &mut self,
16048        direction: Direction,
16049        severity: GoToDiagnosticSeverityFilter,
16050        window: &mut Window,
16051        cx: &mut Context<Self>,
16052    ) {
16053        let buffer = self.buffer.read(cx).snapshot(cx);
16054        let selection = self.selections.newest::<usize>(cx);
16055
16056        let mut active_group_id = None;
16057        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16058            && active_group.active_range.start.to_offset(&buffer) == selection.start
16059        {
16060            active_group_id = Some(active_group.group_id);
16061        }
16062
16063        fn filtered<'a>(
16064            snapshot: EditorSnapshot,
16065            severity: GoToDiagnosticSeverityFilter,
16066            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16067        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16068            diagnostics
16069                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16070                .filter(|entry| entry.range.start != entry.range.end)
16071                .filter(|entry| !entry.diagnostic.is_unnecessary)
16072                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16073        }
16074
16075        let snapshot = self.snapshot(window, cx);
16076        let before = filtered(
16077            snapshot.clone(),
16078            severity,
16079            buffer
16080                .diagnostics_in_range(0..selection.start)
16081                .filter(|entry| entry.range.start <= selection.start),
16082        );
16083        let after = filtered(
16084            snapshot,
16085            severity,
16086            buffer
16087                .diagnostics_in_range(selection.start..buffer.len())
16088                .filter(|entry| entry.range.start >= selection.start),
16089        );
16090
16091        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16092        if direction == Direction::Prev {
16093            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16094            {
16095                for diagnostic in prev_diagnostics.into_iter().rev() {
16096                    if diagnostic.range.start != selection.start
16097                        || active_group_id
16098                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16099                    {
16100                        found = Some(diagnostic);
16101                        break 'outer;
16102                    }
16103                }
16104            }
16105        } else {
16106            for diagnostic in after.chain(before) {
16107                if diagnostic.range.start != selection.start
16108                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16109                {
16110                    found = Some(diagnostic);
16111                    break;
16112                }
16113            }
16114        }
16115        let Some(next_diagnostic) = found else {
16116            return;
16117        };
16118
16119        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16120        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16121            return;
16122        };
16123        self.change_selections(Default::default(), window, cx, |s| {
16124            s.select_ranges(vec![
16125                next_diagnostic.range.start..next_diagnostic.range.start,
16126            ])
16127        });
16128        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16129        self.refresh_edit_prediction(false, true, window, cx);
16130    }
16131
16132    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16133        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16134        let snapshot = self.snapshot(window, cx);
16135        let selection = self.selections.newest::<Point>(cx);
16136        self.go_to_hunk_before_or_after_position(
16137            &snapshot,
16138            selection.head(),
16139            Direction::Next,
16140            window,
16141            cx,
16142        );
16143    }
16144
16145    pub fn go_to_hunk_before_or_after_position(
16146        &mut self,
16147        snapshot: &EditorSnapshot,
16148        position: Point,
16149        direction: Direction,
16150        window: &mut Window,
16151        cx: &mut Context<Editor>,
16152    ) {
16153        let row = if direction == Direction::Next {
16154            self.hunk_after_position(snapshot, position)
16155                .map(|hunk| hunk.row_range.start)
16156        } else {
16157            self.hunk_before_position(snapshot, position)
16158        };
16159
16160        if let Some(row) = row {
16161            let destination = Point::new(row.0, 0);
16162            let autoscroll = Autoscroll::center();
16163
16164            self.unfold_ranges(&[destination..destination], false, false, cx);
16165            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16166                s.select_ranges([destination..destination]);
16167            });
16168        }
16169    }
16170
16171    fn hunk_after_position(
16172        &mut self,
16173        snapshot: &EditorSnapshot,
16174        position: Point,
16175    ) -> Option<MultiBufferDiffHunk> {
16176        snapshot
16177            .buffer_snapshot()
16178            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16179            .find(|hunk| hunk.row_range.start.0 > position.row)
16180            .or_else(|| {
16181                snapshot
16182                    .buffer_snapshot()
16183                    .diff_hunks_in_range(Point::zero()..position)
16184                    .find(|hunk| hunk.row_range.end.0 < position.row)
16185            })
16186    }
16187
16188    fn go_to_prev_hunk(
16189        &mut self,
16190        _: &GoToPreviousHunk,
16191        window: &mut Window,
16192        cx: &mut Context<Self>,
16193    ) {
16194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16195        let snapshot = self.snapshot(window, cx);
16196        let selection = self.selections.newest::<Point>(cx);
16197        self.go_to_hunk_before_or_after_position(
16198            &snapshot,
16199            selection.head(),
16200            Direction::Prev,
16201            window,
16202            cx,
16203        );
16204    }
16205
16206    fn hunk_before_position(
16207        &mut self,
16208        snapshot: &EditorSnapshot,
16209        position: Point,
16210    ) -> Option<MultiBufferRow> {
16211        snapshot
16212            .buffer_snapshot()
16213            .diff_hunk_before(position)
16214            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16215    }
16216
16217    fn go_to_next_change(
16218        &mut self,
16219        _: &GoToNextChange,
16220        window: &mut Window,
16221        cx: &mut Context<Self>,
16222    ) {
16223        if let Some(selections) = self
16224            .change_list
16225            .next_change(1, Direction::Next)
16226            .map(|s| s.to_vec())
16227        {
16228            self.change_selections(Default::default(), window, cx, |s| {
16229                let map = s.display_map();
16230                s.select_display_ranges(selections.iter().map(|a| {
16231                    let point = a.to_display_point(&map);
16232                    point..point
16233                }))
16234            })
16235        }
16236    }
16237
16238    fn go_to_previous_change(
16239        &mut self,
16240        _: &GoToPreviousChange,
16241        window: &mut Window,
16242        cx: &mut Context<Self>,
16243    ) {
16244        if let Some(selections) = self
16245            .change_list
16246            .next_change(1, Direction::Prev)
16247            .map(|s| s.to_vec())
16248        {
16249            self.change_selections(Default::default(), window, cx, |s| {
16250                let map = s.display_map();
16251                s.select_display_ranges(selections.iter().map(|a| {
16252                    let point = a.to_display_point(&map);
16253                    point..point
16254                }))
16255            })
16256        }
16257    }
16258
16259    pub fn go_to_next_document_highlight(
16260        &mut self,
16261        _: &GoToNextDocumentHighlight,
16262        window: &mut Window,
16263        cx: &mut Context<Self>,
16264    ) {
16265        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16266    }
16267
16268    pub fn go_to_prev_document_highlight(
16269        &mut self,
16270        _: &GoToPreviousDocumentHighlight,
16271        window: &mut Window,
16272        cx: &mut Context<Self>,
16273    ) {
16274        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16275    }
16276
16277    pub fn go_to_document_highlight_before_or_after_position(
16278        &mut self,
16279        direction: Direction,
16280        window: &mut Window,
16281        cx: &mut Context<Editor>,
16282    ) {
16283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16284        let snapshot = self.snapshot(window, cx);
16285        let buffer = &snapshot.buffer_snapshot();
16286        let position = self.selections.newest::<Point>(cx).head();
16287        let anchor_position = buffer.anchor_after(position);
16288
16289        // Get all document highlights (both read and write)
16290        let mut all_highlights = Vec::new();
16291
16292        if let Some((_, read_highlights)) = self
16293            .background_highlights
16294            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16295        {
16296            all_highlights.extend(read_highlights.iter());
16297        }
16298
16299        if let Some((_, write_highlights)) = self
16300            .background_highlights
16301            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16302        {
16303            all_highlights.extend(write_highlights.iter());
16304        }
16305
16306        if all_highlights.is_empty() {
16307            return;
16308        }
16309
16310        // Sort highlights by position
16311        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16312
16313        let target_highlight = match direction {
16314            Direction::Next => {
16315                // Find the first highlight after the current position
16316                all_highlights
16317                    .iter()
16318                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16319            }
16320            Direction::Prev => {
16321                // Find the last highlight before the current position
16322                all_highlights
16323                    .iter()
16324                    .rev()
16325                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16326            }
16327        };
16328
16329        if let Some(highlight) = target_highlight {
16330            let destination = highlight.start.to_point(buffer);
16331            let autoscroll = Autoscroll::center();
16332
16333            self.unfold_ranges(&[destination..destination], false, false, cx);
16334            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16335                s.select_ranges([destination..destination]);
16336            });
16337        }
16338    }
16339
16340    fn go_to_line<T: 'static>(
16341        &mut self,
16342        position: Anchor,
16343        highlight_color: Option<Hsla>,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        let snapshot = self.snapshot(window, cx).display_snapshot;
16348        let position = position.to_point(&snapshot.buffer_snapshot());
16349        let start = snapshot
16350            .buffer_snapshot()
16351            .clip_point(Point::new(position.row, 0), Bias::Left);
16352        let end = start + Point::new(1, 0);
16353        let start = snapshot.buffer_snapshot().anchor_before(start);
16354        let end = snapshot.buffer_snapshot().anchor_before(end);
16355
16356        self.highlight_rows::<T>(
16357            start..end,
16358            highlight_color
16359                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16360            Default::default(),
16361            cx,
16362        );
16363
16364        if self.buffer.read(cx).is_singleton() {
16365            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16366        }
16367    }
16368
16369    pub fn go_to_definition(
16370        &mut self,
16371        _: &GoToDefinition,
16372        window: &mut Window,
16373        cx: &mut Context<Self>,
16374    ) -> Task<Result<Navigated>> {
16375        let definition =
16376            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16377        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16378        cx.spawn_in(window, async move |editor, cx| {
16379            if definition.await? == Navigated::Yes {
16380                return Ok(Navigated::Yes);
16381            }
16382            match fallback_strategy {
16383                GoToDefinitionFallback::None => Ok(Navigated::No),
16384                GoToDefinitionFallback::FindAllReferences => {
16385                    match editor.update_in(cx, |editor, window, cx| {
16386                        editor.find_all_references(&FindAllReferences, window, cx)
16387                    })? {
16388                        Some(references) => references.await,
16389                        None => Ok(Navigated::No),
16390                    }
16391                }
16392            }
16393        })
16394    }
16395
16396    pub fn go_to_declaration(
16397        &mut self,
16398        _: &GoToDeclaration,
16399        window: &mut Window,
16400        cx: &mut Context<Self>,
16401    ) -> Task<Result<Navigated>> {
16402        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16403    }
16404
16405    pub fn go_to_declaration_split(
16406        &mut self,
16407        _: &GoToDeclaration,
16408        window: &mut Window,
16409        cx: &mut Context<Self>,
16410    ) -> Task<Result<Navigated>> {
16411        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16412    }
16413
16414    pub fn go_to_implementation(
16415        &mut self,
16416        _: &GoToImplementation,
16417        window: &mut Window,
16418        cx: &mut Context<Self>,
16419    ) -> Task<Result<Navigated>> {
16420        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16421    }
16422
16423    pub fn go_to_implementation_split(
16424        &mut self,
16425        _: &GoToImplementationSplit,
16426        window: &mut Window,
16427        cx: &mut Context<Self>,
16428    ) -> Task<Result<Navigated>> {
16429        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16430    }
16431
16432    pub fn go_to_type_definition(
16433        &mut self,
16434        _: &GoToTypeDefinition,
16435        window: &mut Window,
16436        cx: &mut Context<Self>,
16437    ) -> Task<Result<Navigated>> {
16438        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16439    }
16440
16441    pub fn go_to_definition_split(
16442        &mut self,
16443        _: &GoToDefinitionSplit,
16444        window: &mut Window,
16445        cx: &mut Context<Self>,
16446    ) -> Task<Result<Navigated>> {
16447        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16448    }
16449
16450    pub fn go_to_type_definition_split(
16451        &mut self,
16452        _: &GoToTypeDefinitionSplit,
16453        window: &mut Window,
16454        cx: &mut Context<Self>,
16455    ) -> Task<Result<Navigated>> {
16456        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16457    }
16458
16459    fn go_to_definition_of_kind(
16460        &mut self,
16461        kind: GotoDefinitionKind,
16462        split: bool,
16463        window: &mut Window,
16464        cx: &mut Context<Self>,
16465    ) -> Task<Result<Navigated>> {
16466        let Some(provider) = self.semantics_provider.clone() else {
16467            return Task::ready(Ok(Navigated::No));
16468        };
16469        let head = self.selections.newest::<usize>(cx).head();
16470        let buffer = self.buffer.read(cx);
16471        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16472            return Task::ready(Ok(Navigated::No));
16473        };
16474        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16475            return Task::ready(Ok(Navigated::No));
16476        };
16477
16478        cx.spawn_in(window, async move |editor, cx| {
16479            let Some(definitions) = definitions.await? else {
16480                return Ok(Navigated::No);
16481            };
16482            let navigated = editor
16483                .update_in(cx, |editor, window, cx| {
16484                    editor.navigate_to_hover_links(
16485                        Some(kind),
16486                        definitions
16487                            .into_iter()
16488                            .filter(|location| {
16489                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16490                            })
16491                            .map(HoverLink::Text)
16492                            .collect::<Vec<_>>(),
16493                        split,
16494                        window,
16495                        cx,
16496                    )
16497                })?
16498                .await?;
16499            anyhow::Ok(navigated)
16500        })
16501    }
16502
16503    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16504        let selection = self.selections.newest_anchor();
16505        let head = selection.head();
16506        let tail = selection.tail();
16507
16508        let Some((buffer, start_position)) =
16509            self.buffer.read(cx).text_anchor_for_position(head, cx)
16510        else {
16511            return;
16512        };
16513
16514        let end_position = if head != tail {
16515            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16516                return;
16517            };
16518            Some(pos)
16519        } else {
16520            None
16521        };
16522
16523        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16524            let url = if let Some(end_pos) = end_position {
16525                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16526            } else {
16527                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16528            };
16529
16530            if let Some(url) = url {
16531                cx.update(|window, cx| {
16532                    if parse_zed_link(&url, cx).is_some() {
16533                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16534                    } else {
16535                        cx.open_url(&url);
16536                    }
16537                })?;
16538            }
16539
16540            anyhow::Ok(())
16541        });
16542
16543        url_finder.detach();
16544    }
16545
16546    pub fn open_selected_filename(
16547        &mut self,
16548        _: &OpenSelectedFilename,
16549        window: &mut Window,
16550        cx: &mut Context<Self>,
16551    ) {
16552        let Some(workspace) = self.workspace() else {
16553            return;
16554        };
16555
16556        let position = self.selections.newest_anchor().head();
16557
16558        let Some((buffer, buffer_position)) =
16559            self.buffer.read(cx).text_anchor_for_position(position, cx)
16560        else {
16561            return;
16562        };
16563
16564        let project = self.project.clone();
16565
16566        cx.spawn_in(window, async move |_, cx| {
16567            let result = find_file(&buffer, project, buffer_position, cx).await;
16568
16569            if let Some((_, path)) = result {
16570                workspace
16571                    .update_in(cx, |workspace, window, cx| {
16572                        workspace.open_resolved_path(path, window, cx)
16573                    })?
16574                    .await?;
16575            }
16576            anyhow::Ok(())
16577        })
16578        .detach();
16579    }
16580
16581    pub(crate) fn navigate_to_hover_links(
16582        &mut self,
16583        kind: Option<GotoDefinitionKind>,
16584        definitions: Vec<HoverLink>,
16585        split: bool,
16586        window: &mut Window,
16587        cx: &mut Context<Editor>,
16588    ) -> Task<Result<Navigated>> {
16589        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16590        let mut first_url_or_file = None;
16591        let definitions: Vec<_> = definitions
16592            .into_iter()
16593            .filter_map(|def| match def {
16594                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16595                HoverLink::InlayHint(lsp_location, server_id) => {
16596                    let computation =
16597                        self.compute_target_location(lsp_location, server_id, window, cx);
16598                    Some(cx.background_spawn(computation))
16599                }
16600                HoverLink::Url(url) => {
16601                    first_url_or_file = Some(Either::Left(url));
16602                    None
16603                }
16604                HoverLink::File(path) => {
16605                    first_url_or_file = Some(Either::Right(path));
16606                    None
16607                }
16608            })
16609            .collect();
16610
16611        let workspace = self.workspace();
16612
16613        cx.spawn_in(window, async move |editor, cx| {
16614            let locations: Vec<Location> = future::join_all(definitions)
16615                .await
16616                .into_iter()
16617                .filter_map(|location| location.transpose())
16618                .collect::<Result<_>>()
16619                .context("location tasks")?;
16620            let mut locations = cx.update(|_, cx| {
16621                locations
16622                    .into_iter()
16623                    .map(|location| {
16624                        let buffer = location.buffer.read(cx);
16625                        (location.buffer, location.range.to_point(buffer))
16626                    })
16627                    .into_group_map()
16628            })?;
16629            let mut num_locations = 0;
16630            for ranges in locations.values_mut() {
16631                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16632                ranges.dedup();
16633                num_locations += ranges.len();
16634            }
16635
16636            if num_locations > 1 {
16637                let Some(workspace) = workspace else {
16638                    return Ok(Navigated::No);
16639                };
16640
16641                let tab_kind = match kind {
16642                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16643                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16644                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16645                    Some(GotoDefinitionKind::Type) => "Types",
16646                };
16647                let title = editor
16648                    .update_in(cx, |_, _, cx| {
16649                        let target = locations
16650                            .iter()
16651                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16652                            .map(|(buffer, location)| {
16653                                buffer
16654                                    .read(cx)
16655                                    .text_for_range(location.clone())
16656                                    .collect::<String>()
16657                            })
16658                            .filter(|text| !text.contains('\n'))
16659                            .unique()
16660                            .take(3)
16661                            .join(", ");
16662                        if target.is_empty() {
16663                            tab_kind.to_owned()
16664                        } else {
16665                            format!("{tab_kind} for {target}")
16666                        }
16667                    })
16668                    .context("buffer title")?;
16669
16670                let opened = workspace
16671                    .update_in(cx, |workspace, window, cx| {
16672                        Self::open_locations_in_multibuffer(
16673                            workspace,
16674                            locations,
16675                            title,
16676                            split,
16677                            MultibufferSelectionMode::First,
16678                            window,
16679                            cx,
16680                        )
16681                    })
16682                    .is_ok();
16683
16684                anyhow::Ok(Navigated::from_bool(opened))
16685            } else if num_locations == 0 {
16686                // If there is one url or file, open it directly
16687                match first_url_or_file {
16688                    Some(Either::Left(url)) => {
16689                        cx.update(|_, cx| cx.open_url(&url))?;
16690                        Ok(Navigated::Yes)
16691                    }
16692                    Some(Either::Right(path)) => {
16693                        let Some(workspace) = workspace else {
16694                            return Ok(Navigated::No);
16695                        };
16696
16697                        workspace
16698                            .update_in(cx, |workspace, window, cx| {
16699                                workspace.open_resolved_path(path, window, cx)
16700                            })?
16701                            .await?;
16702                        Ok(Navigated::Yes)
16703                    }
16704                    None => Ok(Navigated::No),
16705                }
16706            } else {
16707                let Some(workspace) = workspace else {
16708                    return Ok(Navigated::No);
16709                };
16710
16711                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16712                let target_range = target_ranges.first().unwrap().clone();
16713
16714                editor.update_in(cx, |editor, window, cx| {
16715                    let range = target_range.to_point(target_buffer.read(cx));
16716                    let range = editor.range_for_match(&range);
16717                    let range = collapse_multiline_range(range);
16718
16719                    if !split
16720                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16721                    {
16722                        editor.go_to_singleton_buffer_range(range, window, cx);
16723                    } else {
16724                        let pane = workspace.read(cx).active_pane().clone();
16725                        window.defer(cx, move |window, cx| {
16726                            let target_editor: Entity<Self> =
16727                                workspace.update(cx, |workspace, cx| {
16728                                    let pane = if split {
16729                                        workspace.adjacent_pane(window, cx)
16730                                    } else {
16731                                        workspace.active_pane().clone()
16732                                    };
16733
16734                                    workspace.open_project_item(
16735                                        pane,
16736                                        target_buffer.clone(),
16737                                        true,
16738                                        true,
16739                                        window,
16740                                        cx,
16741                                    )
16742                                });
16743                            target_editor.update(cx, |target_editor, cx| {
16744                                // When selecting a definition in a different buffer, disable the nav history
16745                                // to avoid creating a history entry at the previous cursor location.
16746                                pane.update(cx, |pane, _| pane.disable_history());
16747                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16748                                pane.update(cx, |pane, _| pane.enable_history());
16749                            });
16750                        });
16751                    }
16752                    Navigated::Yes
16753                })
16754            }
16755        })
16756    }
16757
16758    fn compute_target_location(
16759        &self,
16760        lsp_location: lsp::Location,
16761        server_id: LanguageServerId,
16762        window: &mut Window,
16763        cx: &mut Context<Self>,
16764    ) -> Task<anyhow::Result<Option<Location>>> {
16765        let Some(project) = self.project.clone() else {
16766            return Task::ready(Ok(None));
16767        };
16768
16769        cx.spawn_in(window, async move |editor, cx| {
16770            let location_task = editor.update(cx, |_, cx| {
16771                project.update(cx, |project, cx| {
16772                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16773                })
16774            })?;
16775            let location = Some({
16776                let target_buffer_handle = location_task.await.context("open local buffer")?;
16777                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16778                    let target_start = target_buffer
16779                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16780                    let target_end = target_buffer
16781                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16782                    target_buffer.anchor_after(target_start)
16783                        ..target_buffer.anchor_before(target_end)
16784                })?;
16785                Location {
16786                    buffer: target_buffer_handle,
16787                    range,
16788                }
16789            });
16790            Ok(location)
16791        })
16792    }
16793
16794    pub fn find_all_references(
16795        &mut self,
16796        _: &FindAllReferences,
16797        window: &mut Window,
16798        cx: &mut Context<Self>,
16799    ) -> Option<Task<Result<Navigated>>> {
16800        let selection = self.selections.newest::<usize>(cx);
16801        let multi_buffer = self.buffer.read(cx);
16802        let head = selection.head();
16803
16804        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16805        let head_anchor = multi_buffer_snapshot.anchor_at(
16806            head,
16807            if head < selection.tail() {
16808                Bias::Right
16809            } else {
16810                Bias::Left
16811            },
16812        );
16813
16814        match self
16815            .find_all_references_task_sources
16816            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16817        {
16818            Ok(_) => {
16819                log::info!(
16820                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16821                );
16822                return None;
16823            }
16824            Err(i) => {
16825                self.find_all_references_task_sources.insert(i, head_anchor);
16826            }
16827        }
16828
16829        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16830        let workspace = self.workspace()?;
16831        let project = workspace.read(cx).project().clone();
16832        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16833        Some(cx.spawn_in(window, async move |editor, cx| {
16834            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16835                if let Ok(i) = editor
16836                    .find_all_references_task_sources
16837                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16838                {
16839                    editor.find_all_references_task_sources.remove(i);
16840                }
16841            });
16842
16843            let Some(locations) = references.await? else {
16844                return anyhow::Ok(Navigated::No);
16845            };
16846            let mut locations = cx.update(|_, cx| {
16847                locations
16848                    .into_iter()
16849                    .map(|location| {
16850                        let buffer = location.buffer.read(cx);
16851                        (location.buffer, location.range.to_point(buffer))
16852                    })
16853                    .into_group_map()
16854            })?;
16855            if locations.is_empty() {
16856                return anyhow::Ok(Navigated::No);
16857            }
16858            for ranges in locations.values_mut() {
16859                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16860                ranges.dedup();
16861            }
16862
16863            workspace.update_in(cx, |workspace, window, cx| {
16864                let target = locations
16865                    .iter()
16866                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16867                    .map(|(buffer, location)| {
16868                        buffer
16869                            .read(cx)
16870                            .text_for_range(location.clone())
16871                            .collect::<String>()
16872                    })
16873                    .filter(|text| !text.contains('\n'))
16874                    .unique()
16875                    .take(3)
16876                    .join(", ");
16877                let title = if target.is_empty() {
16878                    "References".to_owned()
16879                } else {
16880                    format!("References to {target}")
16881                };
16882                Self::open_locations_in_multibuffer(
16883                    workspace,
16884                    locations,
16885                    title,
16886                    false,
16887                    MultibufferSelectionMode::First,
16888                    window,
16889                    cx,
16890                );
16891                Navigated::Yes
16892            })
16893        }))
16894    }
16895
16896    /// Opens a multibuffer with the given project locations in it
16897    pub fn open_locations_in_multibuffer(
16898        workspace: &mut Workspace,
16899        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16900        title: String,
16901        split: bool,
16902        multibuffer_selection_mode: MultibufferSelectionMode,
16903        window: &mut Window,
16904        cx: &mut Context<Workspace>,
16905    ) {
16906        if locations.is_empty() {
16907            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16908            return;
16909        }
16910
16911        let capability = workspace.project().read(cx).capability();
16912        let mut ranges = <Vec<Range<Anchor>>>::new();
16913
16914        // a key to find existing multibuffer editors with the same set of locations
16915        // to prevent us from opening more and more multibuffer tabs for searches and the like
16916        let mut key = (title.clone(), vec![]);
16917        let excerpt_buffer = cx.new(|cx| {
16918            let key = &mut key.1;
16919            let mut multibuffer = MultiBuffer::new(capability);
16920            for (buffer, mut ranges_for_buffer) in locations {
16921                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16922                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16923                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16924                    PathKey::for_buffer(&buffer, cx),
16925                    buffer.clone(),
16926                    ranges_for_buffer,
16927                    multibuffer_context_lines(cx),
16928                    cx,
16929                );
16930                ranges.extend(new_ranges)
16931            }
16932
16933            multibuffer.with_title(title)
16934        });
16935        let existing = workspace.active_pane().update(cx, |pane, cx| {
16936            pane.items()
16937                .filter_map(|item| item.downcast::<Editor>())
16938                .find(|editor| {
16939                    editor
16940                        .read(cx)
16941                        .lookup_key
16942                        .as_ref()
16943                        .and_then(|it| {
16944                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16945                        })
16946                        .is_some_and(|it| *it == key)
16947                })
16948        });
16949        let editor = existing.unwrap_or_else(|| {
16950            cx.new(|cx| {
16951                let mut editor = Editor::for_multibuffer(
16952                    excerpt_buffer,
16953                    Some(workspace.project().clone()),
16954                    window,
16955                    cx,
16956                );
16957                editor.lookup_key = Some(Box::new(key));
16958                editor
16959            })
16960        });
16961        editor.update(cx, |editor, cx| {
16962            match multibuffer_selection_mode {
16963                MultibufferSelectionMode::First => {
16964                    if let Some(first_range) = ranges.first() {
16965                        editor.change_selections(
16966                            SelectionEffects::no_scroll(),
16967                            window,
16968                            cx,
16969                            |selections| {
16970                                selections.clear_disjoint();
16971                                selections
16972                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16973                            },
16974                        );
16975                    }
16976                    editor.highlight_background::<Self>(
16977                        &ranges,
16978                        |theme| theme.colors().editor_highlighted_line_background,
16979                        cx,
16980                    );
16981                }
16982                MultibufferSelectionMode::All => {
16983                    editor.change_selections(
16984                        SelectionEffects::no_scroll(),
16985                        window,
16986                        cx,
16987                        |selections| {
16988                            selections.clear_disjoint();
16989                            selections.select_anchor_ranges(ranges);
16990                        },
16991                    );
16992                }
16993            }
16994            editor.register_buffers_with_language_servers(cx);
16995        });
16996
16997        let item = Box::new(editor);
16998        let item_id = item.item_id();
16999
17000        if split {
17001            let pane = workspace.adjacent_pane(window, cx);
17002            workspace.add_item(pane, item, None, true, true, window, cx);
17003        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17004            let (preview_item_id, preview_item_idx) =
17005                workspace.active_pane().read_with(cx, |pane, _| {
17006                    (pane.preview_item_id(), pane.preview_item_idx())
17007                });
17008
17009            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17010
17011            if let Some(preview_item_id) = preview_item_id {
17012                workspace.active_pane().update(cx, |pane, cx| {
17013                    pane.remove_item(preview_item_id, false, false, window, cx);
17014                });
17015            }
17016        } else {
17017            workspace.add_item_to_active_pane(item, None, true, window, cx);
17018        }
17019        workspace.active_pane().update(cx, |pane, cx| {
17020            pane.set_preview_item_id(Some(item_id), cx);
17021        });
17022    }
17023
17024    pub fn rename(
17025        &mut self,
17026        _: &Rename,
17027        window: &mut Window,
17028        cx: &mut Context<Self>,
17029    ) -> Option<Task<Result<()>>> {
17030        use language::ToOffset as _;
17031
17032        let provider = self.semantics_provider.clone()?;
17033        let selection = self.selections.newest_anchor().clone();
17034        let (cursor_buffer, cursor_buffer_position) = self
17035            .buffer
17036            .read(cx)
17037            .text_anchor_for_position(selection.head(), cx)?;
17038        let (tail_buffer, cursor_buffer_position_end) = self
17039            .buffer
17040            .read(cx)
17041            .text_anchor_for_position(selection.tail(), cx)?;
17042        if tail_buffer != cursor_buffer {
17043            return None;
17044        }
17045
17046        let snapshot = cursor_buffer.read(cx).snapshot();
17047        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17048        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17049        let prepare_rename = provider
17050            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17051            .unwrap_or_else(|| Task::ready(Ok(None)));
17052        drop(snapshot);
17053
17054        Some(cx.spawn_in(window, async move |this, cx| {
17055            let rename_range = if let Some(range) = prepare_rename.await? {
17056                Some(range)
17057            } else {
17058                this.update(cx, |this, cx| {
17059                    let buffer = this.buffer.read(cx).snapshot(cx);
17060                    let mut buffer_highlights = this
17061                        .document_highlights_for_position(selection.head(), &buffer)
17062                        .filter(|highlight| {
17063                            highlight.start.excerpt_id == selection.head().excerpt_id
17064                                && highlight.end.excerpt_id == selection.head().excerpt_id
17065                        });
17066                    buffer_highlights
17067                        .next()
17068                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17069                })?
17070            };
17071            if let Some(rename_range) = rename_range {
17072                this.update_in(cx, |this, window, cx| {
17073                    let snapshot = cursor_buffer.read(cx).snapshot();
17074                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17075                    let cursor_offset_in_rename_range =
17076                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17077                    let cursor_offset_in_rename_range_end =
17078                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17079
17080                    this.take_rename(false, window, cx);
17081                    let buffer = this.buffer.read(cx).read(cx);
17082                    let cursor_offset = selection.head().to_offset(&buffer);
17083                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17084                    let rename_end = rename_start + rename_buffer_range.len();
17085                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17086                    let mut old_highlight_id = None;
17087                    let old_name: Arc<str> = buffer
17088                        .chunks(rename_start..rename_end, true)
17089                        .map(|chunk| {
17090                            if old_highlight_id.is_none() {
17091                                old_highlight_id = chunk.syntax_highlight_id;
17092                            }
17093                            chunk.text
17094                        })
17095                        .collect::<String>()
17096                        .into();
17097
17098                    drop(buffer);
17099
17100                    // Position the selection in the rename editor so that it matches the current selection.
17101                    this.show_local_selections = false;
17102                    let rename_editor = cx.new(|cx| {
17103                        let mut editor = Editor::single_line(window, cx);
17104                        editor.buffer.update(cx, |buffer, cx| {
17105                            buffer.edit([(0..0, old_name.clone())], None, cx)
17106                        });
17107                        let rename_selection_range = match cursor_offset_in_rename_range
17108                            .cmp(&cursor_offset_in_rename_range_end)
17109                        {
17110                            Ordering::Equal => {
17111                                editor.select_all(&SelectAll, window, cx);
17112                                return editor;
17113                            }
17114                            Ordering::Less => {
17115                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17116                            }
17117                            Ordering::Greater => {
17118                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17119                            }
17120                        };
17121                        if rename_selection_range.end > old_name.len() {
17122                            editor.select_all(&SelectAll, window, cx);
17123                        } else {
17124                            editor.change_selections(Default::default(), window, cx, |s| {
17125                                s.select_ranges([rename_selection_range]);
17126                            });
17127                        }
17128                        editor
17129                    });
17130                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17131                        if e == &EditorEvent::Focused {
17132                            cx.emit(EditorEvent::FocusedIn)
17133                        }
17134                    })
17135                    .detach();
17136
17137                    let write_highlights =
17138                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17139                    let read_highlights =
17140                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17141                    let ranges = write_highlights
17142                        .iter()
17143                        .flat_map(|(_, ranges)| ranges.iter())
17144                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17145                        .cloned()
17146                        .collect();
17147
17148                    this.highlight_text::<Rename>(
17149                        ranges,
17150                        HighlightStyle {
17151                            fade_out: Some(0.6),
17152                            ..Default::default()
17153                        },
17154                        cx,
17155                    );
17156                    let rename_focus_handle = rename_editor.focus_handle(cx);
17157                    window.focus(&rename_focus_handle);
17158                    let block_id = this.insert_blocks(
17159                        [BlockProperties {
17160                            style: BlockStyle::Flex,
17161                            placement: BlockPlacement::Below(range.start),
17162                            height: Some(1),
17163                            render: Arc::new({
17164                                let rename_editor = rename_editor.clone();
17165                                move |cx: &mut BlockContext| {
17166                                    let mut text_style = cx.editor_style.text.clone();
17167                                    if let Some(highlight_style) = old_highlight_id
17168                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17169                                    {
17170                                        text_style = text_style.highlight(highlight_style);
17171                                    }
17172                                    div()
17173                                        .block_mouse_except_scroll()
17174                                        .pl(cx.anchor_x)
17175                                        .child(EditorElement::new(
17176                                            &rename_editor,
17177                                            EditorStyle {
17178                                                background: cx.theme().system().transparent,
17179                                                local_player: cx.editor_style.local_player,
17180                                                text: text_style,
17181                                                scrollbar_width: cx.editor_style.scrollbar_width,
17182                                                syntax: cx.editor_style.syntax.clone(),
17183                                                status: cx.editor_style.status.clone(),
17184                                                inlay_hints_style: HighlightStyle {
17185                                                    font_weight: Some(FontWeight::BOLD),
17186                                                    ..make_inlay_hints_style(cx.app)
17187                                                },
17188                                                edit_prediction_styles: make_suggestion_styles(
17189                                                    cx.app,
17190                                                ),
17191                                                ..EditorStyle::default()
17192                                            },
17193                                        ))
17194                                        .into_any_element()
17195                                }
17196                            }),
17197                            priority: 0,
17198                        }],
17199                        Some(Autoscroll::fit()),
17200                        cx,
17201                    )[0];
17202                    this.pending_rename = Some(RenameState {
17203                        range,
17204                        old_name,
17205                        editor: rename_editor,
17206                        block_id,
17207                    });
17208                })?;
17209            }
17210
17211            Ok(())
17212        }))
17213    }
17214
17215    pub fn confirm_rename(
17216        &mut self,
17217        _: &ConfirmRename,
17218        window: &mut Window,
17219        cx: &mut Context<Self>,
17220    ) -> Option<Task<Result<()>>> {
17221        let rename = self.take_rename(false, window, cx)?;
17222        let workspace = self.workspace()?.downgrade();
17223        let (buffer, start) = self
17224            .buffer
17225            .read(cx)
17226            .text_anchor_for_position(rename.range.start, cx)?;
17227        let (end_buffer, _) = self
17228            .buffer
17229            .read(cx)
17230            .text_anchor_for_position(rename.range.end, cx)?;
17231        if buffer != end_buffer {
17232            return None;
17233        }
17234
17235        let old_name = rename.old_name;
17236        let new_name = rename.editor.read(cx).text(cx);
17237
17238        let rename = self.semantics_provider.as_ref()?.perform_rename(
17239            &buffer,
17240            start,
17241            new_name.clone(),
17242            cx,
17243        )?;
17244
17245        Some(cx.spawn_in(window, async move |editor, cx| {
17246            let project_transaction = rename.await?;
17247            Self::open_project_transaction(
17248                &editor,
17249                workspace,
17250                project_transaction,
17251                format!("Rename: {}{}", old_name, new_name),
17252                cx,
17253            )
17254            .await?;
17255
17256            editor.update(cx, |editor, cx| {
17257                editor.refresh_document_highlights(cx);
17258            })?;
17259            Ok(())
17260        }))
17261    }
17262
17263    fn take_rename(
17264        &mut self,
17265        moving_cursor: bool,
17266        window: &mut Window,
17267        cx: &mut Context<Self>,
17268    ) -> Option<RenameState> {
17269        let rename = self.pending_rename.take()?;
17270        if rename.editor.focus_handle(cx).is_focused(window) {
17271            window.focus(&self.focus_handle);
17272        }
17273
17274        self.remove_blocks(
17275            [rename.block_id].into_iter().collect(),
17276            Some(Autoscroll::fit()),
17277            cx,
17278        );
17279        self.clear_highlights::<Rename>(cx);
17280        self.show_local_selections = true;
17281
17282        if moving_cursor {
17283            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17284                editor.selections.newest::<usize>(cx).head()
17285            });
17286
17287            // Update the selection to match the position of the selection inside
17288            // the rename editor.
17289            let snapshot = self.buffer.read(cx).read(cx);
17290            let rename_range = rename.range.to_offset(&snapshot);
17291            let cursor_in_editor = snapshot
17292                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17293                .min(rename_range.end);
17294            drop(snapshot);
17295
17296            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17297                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17298            });
17299        } else {
17300            self.refresh_document_highlights(cx);
17301        }
17302
17303        Some(rename)
17304    }
17305
17306    pub fn pending_rename(&self) -> Option<&RenameState> {
17307        self.pending_rename.as_ref()
17308    }
17309
17310    fn format(
17311        &mut self,
17312        _: &Format,
17313        window: &mut Window,
17314        cx: &mut Context<Self>,
17315    ) -> Option<Task<Result<()>>> {
17316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17317
17318        let project = match &self.project {
17319            Some(project) => project.clone(),
17320            None => return None,
17321        };
17322
17323        Some(self.perform_format(
17324            project,
17325            FormatTrigger::Manual,
17326            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17327            window,
17328            cx,
17329        ))
17330    }
17331
17332    fn format_selections(
17333        &mut self,
17334        _: &FormatSelections,
17335        window: &mut Window,
17336        cx: &mut Context<Self>,
17337    ) -> Option<Task<Result<()>>> {
17338        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17339
17340        let project = match &self.project {
17341            Some(project) => project.clone(),
17342            None => return None,
17343        };
17344
17345        let ranges = self
17346            .selections
17347            .all_adjusted(cx)
17348            .into_iter()
17349            .map(|selection| selection.range())
17350            .collect_vec();
17351
17352        Some(self.perform_format(
17353            project,
17354            FormatTrigger::Manual,
17355            FormatTarget::Ranges(ranges),
17356            window,
17357            cx,
17358        ))
17359    }
17360
17361    fn perform_format(
17362        &mut self,
17363        project: Entity<Project>,
17364        trigger: FormatTrigger,
17365        target: FormatTarget,
17366        window: &mut Window,
17367        cx: &mut Context<Self>,
17368    ) -> Task<Result<()>> {
17369        let buffer = self.buffer.clone();
17370        let (buffers, target) = match target {
17371            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17372            FormatTarget::Ranges(selection_ranges) => {
17373                let multi_buffer = buffer.read(cx);
17374                let snapshot = multi_buffer.read(cx);
17375                let mut buffers = HashSet::default();
17376                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17377                    BTreeMap::new();
17378                for selection_range in selection_ranges {
17379                    for (buffer, buffer_range, _) in
17380                        snapshot.range_to_buffer_ranges(selection_range)
17381                    {
17382                        let buffer_id = buffer.remote_id();
17383                        let start = buffer.anchor_before(buffer_range.start);
17384                        let end = buffer.anchor_after(buffer_range.end);
17385                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17386                        buffer_id_to_ranges
17387                            .entry(buffer_id)
17388                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17389                            .or_insert_with(|| vec![start..end]);
17390                    }
17391                }
17392                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17393            }
17394        };
17395
17396        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17397        let selections_prev = transaction_id_prev
17398            .and_then(|transaction_id_prev| {
17399                // default to selections as they were after the last edit, if we have them,
17400                // instead of how they are now.
17401                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17402                // will take you back to where you made the last edit, instead of staying where you scrolled
17403                self.selection_history
17404                    .transaction(transaction_id_prev)
17405                    .map(|t| t.0.clone())
17406            })
17407            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17408
17409        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17410        let format = project.update(cx, |project, cx| {
17411            project.format(buffers, target, true, trigger, cx)
17412        });
17413
17414        cx.spawn_in(window, async move |editor, cx| {
17415            let transaction = futures::select_biased! {
17416                transaction = format.log_err().fuse() => transaction,
17417                () = timeout => {
17418                    log::warn!("timed out waiting for formatting");
17419                    None
17420                }
17421            };
17422
17423            buffer
17424                .update(cx, |buffer, cx| {
17425                    if let Some(transaction) = transaction
17426                        && !buffer.is_singleton()
17427                    {
17428                        buffer.push_transaction(&transaction.0, cx);
17429                    }
17430                    cx.notify();
17431                })
17432                .ok();
17433
17434            if let Some(transaction_id_now) =
17435                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17436            {
17437                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17438                if has_new_transaction {
17439                    _ = editor.update(cx, |editor, _| {
17440                        editor
17441                            .selection_history
17442                            .insert_transaction(transaction_id_now, selections_prev);
17443                    });
17444                }
17445            }
17446
17447            Ok(())
17448        })
17449    }
17450
17451    fn organize_imports(
17452        &mut self,
17453        _: &OrganizeImports,
17454        window: &mut Window,
17455        cx: &mut Context<Self>,
17456    ) -> Option<Task<Result<()>>> {
17457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17458        let project = match &self.project {
17459            Some(project) => project.clone(),
17460            None => return None,
17461        };
17462        Some(self.perform_code_action_kind(
17463            project,
17464            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17465            window,
17466            cx,
17467        ))
17468    }
17469
17470    fn perform_code_action_kind(
17471        &mut self,
17472        project: Entity<Project>,
17473        kind: CodeActionKind,
17474        window: &mut Window,
17475        cx: &mut Context<Self>,
17476    ) -> Task<Result<()>> {
17477        let buffer = self.buffer.clone();
17478        let buffers = buffer.read(cx).all_buffers();
17479        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17480        let apply_action = project.update(cx, |project, cx| {
17481            project.apply_code_action_kind(buffers, kind, true, cx)
17482        });
17483        cx.spawn_in(window, async move |_, cx| {
17484            let transaction = futures::select_biased! {
17485                () = timeout => {
17486                    log::warn!("timed out waiting for executing code action");
17487                    None
17488                }
17489                transaction = apply_action.log_err().fuse() => transaction,
17490            };
17491            buffer
17492                .update(cx, |buffer, cx| {
17493                    // check if we need this
17494                    if let Some(transaction) = transaction
17495                        && !buffer.is_singleton()
17496                    {
17497                        buffer.push_transaction(&transaction.0, cx);
17498                    }
17499                    cx.notify();
17500                })
17501                .ok();
17502            Ok(())
17503        })
17504    }
17505
17506    pub fn restart_language_server(
17507        &mut self,
17508        _: &RestartLanguageServer,
17509        _: &mut Window,
17510        cx: &mut Context<Self>,
17511    ) {
17512        if let Some(project) = self.project.clone() {
17513            self.buffer.update(cx, |multi_buffer, cx| {
17514                project.update(cx, |project, cx| {
17515                    project.restart_language_servers_for_buffers(
17516                        multi_buffer.all_buffers().into_iter().collect(),
17517                        HashSet::default(),
17518                        cx,
17519                    );
17520                });
17521            })
17522        }
17523    }
17524
17525    pub fn stop_language_server(
17526        &mut self,
17527        _: &StopLanguageServer,
17528        _: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        if let Some(project) = self.project.clone() {
17532            self.buffer.update(cx, |multi_buffer, cx| {
17533                project.update(cx, |project, cx| {
17534                    project.stop_language_servers_for_buffers(
17535                        multi_buffer.all_buffers().into_iter().collect(),
17536                        HashSet::default(),
17537                        cx,
17538                    );
17539                    cx.emit(project::Event::RefreshInlayHints);
17540                });
17541            });
17542        }
17543    }
17544
17545    fn cancel_language_server_work(
17546        workspace: &mut Workspace,
17547        _: &actions::CancelLanguageServerWork,
17548        _: &mut Window,
17549        cx: &mut Context<Workspace>,
17550    ) {
17551        let project = workspace.project();
17552        let buffers = workspace
17553            .active_item(cx)
17554            .and_then(|item| item.act_as::<Editor>(cx))
17555            .map_or(HashSet::default(), |editor| {
17556                editor.read(cx).buffer.read(cx).all_buffers()
17557            });
17558        project.update(cx, |project, cx| {
17559            project.cancel_language_server_work_for_buffers(buffers, cx);
17560        });
17561    }
17562
17563    fn show_character_palette(
17564        &mut self,
17565        _: &ShowCharacterPalette,
17566        window: &mut Window,
17567        _: &mut Context<Self>,
17568    ) {
17569        window.show_character_palette();
17570    }
17571
17572    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17573        if !self.diagnostics_enabled() {
17574            return;
17575        }
17576
17577        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17578            let buffer = self.buffer.read(cx).snapshot(cx);
17579            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17580            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17581            let is_valid = buffer
17582                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17583                .any(|entry| {
17584                    entry.diagnostic.is_primary
17585                        && !entry.range.is_empty()
17586                        && entry.range.start == primary_range_start
17587                        && entry.diagnostic.message == active_diagnostics.active_message
17588                });
17589
17590            if !is_valid {
17591                self.dismiss_diagnostics(cx);
17592            }
17593        }
17594    }
17595
17596    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17597        match &self.active_diagnostics {
17598            ActiveDiagnostic::Group(group) => Some(group),
17599            _ => None,
17600        }
17601    }
17602
17603    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17604        if !self.diagnostics_enabled() {
17605            return;
17606        }
17607        self.dismiss_diagnostics(cx);
17608        self.active_diagnostics = ActiveDiagnostic::All;
17609    }
17610
17611    fn activate_diagnostics(
17612        &mut self,
17613        buffer_id: BufferId,
17614        diagnostic: DiagnosticEntryRef<'_, usize>,
17615        window: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) {
17618        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17619            return;
17620        }
17621        self.dismiss_diagnostics(cx);
17622        let snapshot = self.snapshot(window, cx);
17623        let buffer = self.buffer.read(cx).snapshot(cx);
17624        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17625            return;
17626        };
17627
17628        let diagnostic_group = buffer
17629            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17630            .collect::<Vec<_>>();
17631
17632        let blocks =
17633            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17634
17635        let blocks = self.display_map.update(cx, |display_map, cx| {
17636            display_map.insert_blocks(blocks, cx).into_iter().collect()
17637        });
17638        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17639            active_range: buffer.anchor_before(diagnostic.range.start)
17640                ..buffer.anchor_after(diagnostic.range.end),
17641            active_message: diagnostic.diagnostic.message.clone(),
17642            group_id: diagnostic.diagnostic.group_id,
17643            blocks,
17644        });
17645        cx.notify();
17646    }
17647
17648    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17649        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17650            return;
17651        };
17652
17653        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17654        if let ActiveDiagnostic::Group(group) = prev {
17655            self.display_map.update(cx, |display_map, cx| {
17656                display_map.remove_blocks(group.blocks, cx);
17657            });
17658            cx.notify();
17659        }
17660    }
17661
17662    /// Disable inline diagnostics rendering for this editor.
17663    pub fn disable_inline_diagnostics(&mut self) {
17664        self.inline_diagnostics_enabled = false;
17665        self.inline_diagnostics_update = Task::ready(());
17666        self.inline_diagnostics.clear();
17667    }
17668
17669    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17670        self.diagnostics_enabled = false;
17671        self.dismiss_diagnostics(cx);
17672        self.inline_diagnostics_update = Task::ready(());
17673        self.inline_diagnostics.clear();
17674    }
17675
17676    pub fn disable_word_completions(&mut self) {
17677        self.word_completions_enabled = false;
17678    }
17679
17680    pub fn diagnostics_enabled(&self) -> bool {
17681        self.diagnostics_enabled && self.mode.is_full()
17682    }
17683
17684    pub fn inline_diagnostics_enabled(&self) -> bool {
17685        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17686    }
17687
17688    pub fn show_inline_diagnostics(&self) -> bool {
17689        self.show_inline_diagnostics
17690    }
17691
17692    pub fn toggle_inline_diagnostics(
17693        &mut self,
17694        _: &ToggleInlineDiagnostics,
17695        window: &mut Window,
17696        cx: &mut Context<Editor>,
17697    ) {
17698        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17699        self.refresh_inline_diagnostics(false, window, cx);
17700    }
17701
17702    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17703        self.diagnostics_max_severity = severity;
17704        self.display_map.update(cx, |display_map, _| {
17705            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17706        });
17707    }
17708
17709    pub fn toggle_diagnostics(
17710        &mut self,
17711        _: &ToggleDiagnostics,
17712        window: &mut Window,
17713        cx: &mut Context<Editor>,
17714    ) {
17715        if !self.diagnostics_enabled() {
17716            return;
17717        }
17718
17719        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17720            EditorSettings::get_global(cx)
17721                .diagnostics_max_severity
17722                .filter(|severity| severity != &DiagnosticSeverity::Off)
17723                .unwrap_or(DiagnosticSeverity::Hint)
17724        } else {
17725            DiagnosticSeverity::Off
17726        };
17727        self.set_max_diagnostics_severity(new_severity, cx);
17728        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17729            self.active_diagnostics = ActiveDiagnostic::None;
17730            self.inline_diagnostics_update = Task::ready(());
17731            self.inline_diagnostics.clear();
17732        } else {
17733            self.refresh_inline_diagnostics(false, window, cx);
17734        }
17735
17736        cx.notify();
17737    }
17738
17739    pub fn toggle_minimap(
17740        &mut self,
17741        _: &ToggleMinimap,
17742        window: &mut Window,
17743        cx: &mut Context<Editor>,
17744    ) {
17745        if self.supports_minimap(cx) {
17746            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17747        }
17748    }
17749
17750    fn refresh_inline_diagnostics(
17751        &mut self,
17752        debounce: bool,
17753        window: &mut Window,
17754        cx: &mut Context<Self>,
17755    ) {
17756        let max_severity = ProjectSettings::get_global(cx)
17757            .diagnostics
17758            .inline
17759            .max_severity
17760            .unwrap_or(self.diagnostics_max_severity);
17761
17762        if !self.inline_diagnostics_enabled()
17763            || !self.show_inline_diagnostics
17764            || max_severity == DiagnosticSeverity::Off
17765        {
17766            self.inline_diagnostics_update = Task::ready(());
17767            self.inline_diagnostics.clear();
17768            return;
17769        }
17770
17771        let debounce_ms = ProjectSettings::get_global(cx)
17772            .diagnostics
17773            .inline
17774            .update_debounce_ms;
17775        let debounce = if debounce && debounce_ms > 0 {
17776            Some(Duration::from_millis(debounce_ms))
17777        } else {
17778            None
17779        };
17780        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17781            if let Some(debounce) = debounce {
17782                cx.background_executor().timer(debounce).await;
17783            }
17784            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17785                editor
17786                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17787                    .ok()
17788            }) else {
17789                return;
17790            };
17791
17792            let new_inline_diagnostics = cx
17793                .background_spawn(async move {
17794                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17795                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17796                        let message = diagnostic_entry
17797                            .diagnostic
17798                            .message
17799                            .split_once('\n')
17800                            .map(|(line, _)| line)
17801                            .map(SharedString::new)
17802                            .unwrap_or_else(|| {
17803                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17804                            });
17805                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17806                        let (Ok(i) | Err(i)) = inline_diagnostics
17807                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17808                        inline_diagnostics.insert(
17809                            i,
17810                            (
17811                                start_anchor,
17812                                InlineDiagnostic {
17813                                    message,
17814                                    group_id: diagnostic_entry.diagnostic.group_id,
17815                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17816                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17817                                    severity: diagnostic_entry.diagnostic.severity,
17818                                },
17819                            ),
17820                        );
17821                    }
17822                    inline_diagnostics
17823                })
17824                .await;
17825
17826            editor
17827                .update(cx, |editor, cx| {
17828                    editor.inline_diagnostics = new_inline_diagnostics;
17829                    cx.notify();
17830                })
17831                .ok();
17832        });
17833    }
17834
17835    fn pull_diagnostics(
17836        &mut self,
17837        buffer_id: Option<BufferId>,
17838        window: &Window,
17839        cx: &mut Context<Self>,
17840    ) -> Option<()> {
17841        if !self.mode().is_full() {
17842            return None;
17843        }
17844        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17845            .diagnostics
17846            .lsp_pull_diagnostics;
17847        if !pull_diagnostics_settings.enabled {
17848            return None;
17849        }
17850        let project = self.project()?.downgrade();
17851        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17852        let mut buffers = self.buffer.read(cx).all_buffers();
17853        if let Some(buffer_id) = buffer_id {
17854            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17855        }
17856
17857        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17858            cx.background_executor().timer(debounce).await;
17859
17860            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17861                buffers
17862                    .into_iter()
17863                    .filter_map(|buffer| {
17864                        project
17865                            .update(cx, |project, cx| {
17866                                project.lsp_store().update(cx, |lsp_store, cx| {
17867                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17868                                })
17869                            })
17870                            .ok()
17871                    })
17872                    .collect::<FuturesUnordered<_>>()
17873            }) else {
17874                return;
17875            };
17876
17877            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17878                match pull_task {
17879                    Ok(()) => {
17880                        if editor
17881                            .update_in(cx, |editor, window, cx| {
17882                                editor.update_diagnostics_state(window, cx);
17883                            })
17884                            .is_err()
17885                        {
17886                            return;
17887                        }
17888                    }
17889                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17890                }
17891            }
17892        });
17893
17894        Some(())
17895    }
17896
17897    pub fn set_selections_from_remote(
17898        &mut self,
17899        selections: Vec<Selection<Anchor>>,
17900        pending_selection: Option<Selection<Anchor>>,
17901        window: &mut Window,
17902        cx: &mut Context<Self>,
17903    ) {
17904        let old_cursor_position = self.selections.newest_anchor().head();
17905        self.selections.change_with(cx, |s| {
17906            s.select_anchors(selections);
17907            if let Some(pending_selection) = pending_selection {
17908                s.set_pending(pending_selection, SelectMode::Character);
17909            } else {
17910                s.clear_pending();
17911            }
17912        });
17913        self.selections_did_change(
17914            false,
17915            &old_cursor_position,
17916            SelectionEffects::default(),
17917            window,
17918            cx,
17919        );
17920    }
17921
17922    pub fn transact(
17923        &mut self,
17924        window: &mut Window,
17925        cx: &mut Context<Self>,
17926        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17927    ) -> Option<TransactionId> {
17928        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17929            this.start_transaction_at(Instant::now(), window, cx);
17930            update(this, window, cx);
17931            this.end_transaction_at(Instant::now(), cx)
17932        })
17933    }
17934
17935    pub fn start_transaction_at(
17936        &mut self,
17937        now: Instant,
17938        window: &mut Window,
17939        cx: &mut Context<Self>,
17940    ) -> Option<TransactionId> {
17941        self.end_selection(window, cx);
17942        if let Some(tx_id) = self
17943            .buffer
17944            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17945        {
17946            self.selection_history
17947                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17948            cx.emit(EditorEvent::TransactionBegun {
17949                transaction_id: tx_id,
17950            });
17951            Some(tx_id)
17952        } else {
17953            None
17954        }
17955    }
17956
17957    pub fn end_transaction_at(
17958        &mut self,
17959        now: Instant,
17960        cx: &mut Context<Self>,
17961    ) -> Option<TransactionId> {
17962        if let Some(transaction_id) = self
17963            .buffer
17964            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17965        {
17966            if let Some((_, end_selections)) =
17967                self.selection_history.transaction_mut(transaction_id)
17968            {
17969                *end_selections = Some(self.selections.disjoint_anchors_arc());
17970            } else {
17971                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17972            }
17973
17974            cx.emit(EditorEvent::Edited { transaction_id });
17975            Some(transaction_id)
17976        } else {
17977            None
17978        }
17979    }
17980
17981    pub fn modify_transaction_selection_history(
17982        &mut self,
17983        transaction_id: TransactionId,
17984        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17985    ) -> bool {
17986        self.selection_history
17987            .transaction_mut(transaction_id)
17988            .map(modify)
17989            .is_some()
17990    }
17991
17992    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17993        if self.selection_mark_mode {
17994            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17995                s.move_with(|_, sel| {
17996                    sel.collapse_to(sel.head(), SelectionGoal::None);
17997                });
17998            })
17999        }
18000        self.selection_mark_mode = true;
18001        cx.notify();
18002    }
18003
18004    pub fn swap_selection_ends(
18005        &mut self,
18006        _: &actions::SwapSelectionEnds,
18007        window: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) {
18010        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18011            s.move_with(|_, sel| {
18012                if sel.start != sel.end {
18013                    sel.reversed = !sel.reversed
18014                }
18015            });
18016        });
18017        self.request_autoscroll(Autoscroll::newest(), cx);
18018        cx.notify();
18019    }
18020
18021    pub fn toggle_focus(
18022        workspace: &mut Workspace,
18023        _: &actions::ToggleFocus,
18024        window: &mut Window,
18025        cx: &mut Context<Workspace>,
18026    ) {
18027        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18028            return;
18029        };
18030        workspace.activate_item(&item, true, true, window, cx);
18031    }
18032
18033    pub fn toggle_fold(
18034        &mut self,
18035        _: &actions::ToggleFold,
18036        window: &mut Window,
18037        cx: &mut Context<Self>,
18038    ) {
18039        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18040            let selection = self.selections.newest::<Point>(cx);
18041
18042            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18043            let range = if selection.is_empty() {
18044                let point = selection.head().to_display_point(&display_map);
18045                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18046                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18047                    .to_point(&display_map);
18048                start..end
18049            } else {
18050                selection.range()
18051            };
18052            if display_map.folds_in_range(range).next().is_some() {
18053                self.unfold_lines(&Default::default(), window, cx)
18054            } else {
18055                self.fold(&Default::default(), window, cx)
18056            }
18057        } else {
18058            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18059            let buffer_ids: HashSet<_> = self
18060                .selections
18061                .disjoint_anchor_ranges()
18062                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18063                .collect();
18064
18065            let should_unfold = buffer_ids
18066                .iter()
18067                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18068
18069            for buffer_id in buffer_ids {
18070                if should_unfold {
18071                    self.unfold_buffer(buffer_id, cx);
18072                } else {
18073                    self.fold_buffer(buffer_id, cx);
18074                }
18075            }
18076        }
18077    }
18078
18079    pub fn toggle_fold_recursive(
18080        &mut self,
18081        _: &actions::ToggleFoldRecursive,
18082        window: &mut Window,
18083        cx: &mut Context<Self>,
18084    ) {
18085        let selection = self.selections.newest::<Point>(cx);
18086
18087        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18088        let range = if selection.is_empty() {
18089            let point = selection.head().to_display_point(&display_map);
18090            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18091            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18092                .to_point(&display_map);
18093            start..end
18094        } else {
18095            selection.range()
18096        };
18097        if display_map.folds_in_range(range).next().is_some() {
18098            self.unfold_recursive(&Default::default(), window, cx)
18099        } else {
18100            self.fold_recursive(&Default::default(), window, cx)
18101        }
18102    }
18103
18104    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18105        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18106            let mut to_fold = Vec::new();
18107            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18108            let selections = self.selections.all_adjusted(cx);
18109
18110            for selection in selections {
18111                let range = selection.range().sorted();
18112                let buffer_start_row = range.start.row;
18113
18114                if range.start.row != range.end.row {
18115                    let mut found = false;
18116                    let mut row = range.start.row;
18117                    while row <= range.end.row {
18118                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18119                        {
18120                            found = true;
18121                            row = crease.range().end.row + 1;
18122                            to_fold.push(crease);
18123                        } else {
18124                            row += 1
18125                        }
18126                    }
18127                    if found {
18128                        continue;
18129                    }
18130                }
18131
18132                for row in (0..=range.start.row).rev() {
18133                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18134                        && crease.range().end.row >= buffer_start_row
18135                    {
18136                        to_fold.push(crease);
18137                        if row <= range.start.row {
18138                            break;
18139                        }
18140                    }
18141                }
18142            }
18143
18144            self.fold_creases(to_fold, true, window, cx);
18145        } else {
18146            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18147            let buffer_ids = self
18148                .selections
18149                .disjoint_anchor_ranges()
18150                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18151                .collect::<HashSet<_>>();
18152            for buffer_id in buffer_ids {
18153                self.fold_buffer(buffer_id, cx);
18154            }
18155        }
18156    }
18157
18158    pub fn toggle_fold_all(
18159        &mut self,
18160        _: &actions::ToggleFoldAll,
18161        window: &mut Window,
18162        cx: &mut Context<Self>,
18163    ) {
18164        if self.buffer.read(cx).is_singleton() {
18165            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18166            let has_folds = display_map
18167                .folds_in_range(0..display_map.buffer_snapshot().len())
18168                .next()
18169                .is_some();
18170
18171            if has_folds {
18172                self.unfold_all(&actions::UnfoldAll, window, cx);
18173            } else {
18174                self.fold_all(&actions::FoldAll, window, cx);
18175            }
18176        } else {
18177            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18178            let should_unfold = buffer_ids
18179                .iter()
18180                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18181
18182            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18183                editor
18184                    .update_in(cx, |editor, _, cx| {
18185                        for buffer_id in buffer_ids {
18186                            if should_unfold {
18187                                editor.unfold_buffer(buffer_id, cx);
18188                            } else {
18189                                editor.fold_buffer(buffer_id, cx);
18190                            }
18191                        }
18192                    })
18193                    .ok();
18194            });
18195        }
18196    }
18197
18198    fn fold_at_level(
18199        &mut self,
18200        fold_at: &FoldAtLevel,
18201        window: &mut Window,
18202        cx: &mut Context<Self>,
18203    ) {
18204        if !self.buffer.read(cx).is_singleton() {
18205            return;
18206        }
18207
18208        let fold_at_level = fold_at.0;
18209        let snapshot = self.buffer.read(cx).snapshot(cx);
18210        let mut to_fold = Vec::new();
18211        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18212
18213        let row_ranges_to_keep: Vec<Range<u32>> = self
18214            .selections
18215            .all::<Point>(cx)
18216            .into_iter()
18217            .map(|sel| sel.start.row..sel.end.row)
18218            .collect();
18219
18220        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18221            while start_row < end_row {
18222                match self
18223                    .snapshot(window, cx)
18224                    .crease_for_buffer_row(MultiBufferRow(start_row))
18225                {
18226                    Some(crease) => {
18227                        let nested_start_row = crease.range().start.row + 1;
18228                        let nested_end_row = crease.range().end.row;
18229
18230                        if current_level < fold_at_level {
18231                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18232                        } else if current_level == fold_at_level {
18233                            // Fold iff there is no selection completely contained within the fold region
18234                            if !row_ranges_to_keep.iter().any(|selection| {
18235                                selection.end >= nested_start_row
18236                                    && selection.start <= nested_end_row
18237                            }) {
18238                                to_fold.push(crease);
18239                            }
18240                        }
18241
18242                        start_row = nested_end_row + 1;
18243                    }
18244                    None => start_row += 1,
18245                }
18246            }
18247        }
18248
18249        self.fold_creases(to_fold, true, window, cx);
18250    }
18251
18252    pub fn fold_at_level_1(
18253        &mut self,
18254        _: &actions::FoldAtLevel1,
18255        window: &mut Window,
18256        cx: &mut Context<Self>,
18257    ) {
18258        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18259    }
18260
18261    pub fn fold_at_level_2(
18262        &mut self,
18263        _: &actions::FoldAtLevel2,
18264        window: &mut Window,
18265        cx: &mut Context<Self>,
18266    ) {
18267        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18268    }
18269
18270    pub fn fold_at_level_3(
18271        &mut self,
18272        _: &actions::FoldAtLevel3,
18273        window: &mut Window,
18274        cx: &mut Context<Self>,
18275    ) {
18276        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18277    }
18278
18279    pub fn fold_at_level_4(
18280        &mut self,
18281        _: &actions::FoldAtLevel4,
18282        window: &mut Window,
18283        cx: &mut Context<Self>,
18284    ) {
18285        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18286    }
18287
18288    pub fn fold_at_level_5(
18289        &mut self,
18290        _: &actions::FoldAtLevel5,
18291        window: &mut Window,
18292        cx: &mut Context<Self>,
18293    ) {
18294        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18295    }
18296
18297    pub fn fold_at_level_6(
18298        &mut self,
18299        _: &actions::FoldAtLevel6,
18300        window: &mut Window,
18301        cx: &mut Context<Self>,
18302    ) {
18303        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18304    }
18305
18306    pub fn fold_at_level_7(
18307        &mut self,
18308        _: &actions::FoldAtLevel7,
18309        window: &mut Window,
18310        cx: &mut Context<Self>,
18311    ) {
18312        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18313    }
18314
18315    pub fn fold_at_level_8(
18316        &mut self,
18317        _: &actions::FoldAtLevel8,
18318        window: &mut Window,
18319        cx: &mut Context<Self>,
18320    ) {
18321        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18322    }
18323
18324    pub fn fold_at_level_9(
18325        &mut self,
18326        _: &actions::FoldAtLevel9,
18327        window: &mut Window,
18328        cx: &mut Context<Self>,
18329    ) {
18330        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18331    }
18332
18333    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18334        if self.buffer.read(cx).is_singleton() {
18335            let mut fold_ranges = Vec::new();
18336            let snapshot = self.buffer.read(cx).snapshot(cx);
18337
18338            for row in 0..snapshot.max_row().0 {
18339                if let Some(foldable_range) = self
18340                    .snapshot(window, cx)
18341                    .crease_for_buffer_row(MultiBufferRow(row))
18342                {
18343                    fold_ranges.push(foldable_range);
18344                }
18345            }
18346
18347            self.fold_creases(fold_ranges, true, window, cx);
18348        } else {
18349            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18350                editor
18351                    .update_in(cx, |editor, _, cx| {
18352                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18353                            editor.fold_buffer(buffer_id, cx);
18354                        }
18355                    })
18356                    .ok();
18357            });
18358        }
18359    }
18360
18361    pub fn fold_function_bodies(
18362        &mut self,
18363        _: &actions::FoldFunctionBodies,
18364        window: &mut Window,
18365        cx: &mut Context<Self>,
18366    ) {
18367        let snapshot = self.buffer.read(cx).snapshot(cx);
18368
18369        let ranges = snapshot
18370            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18371            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18372            .collect::<Vec<_>>();
18373
18374        let creases = ranges
18375            .into_iter()
18376            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18377            .collect();
18378
18379        self.fold_creases(creases, true, window, cx);
18380    }
18381
18382    pub fn fold_recursive(
18383        &mut self,
18384        _: &actions::FoldRecursive,
18385        window: &mut Window,
18386        cx: &mut Context<Self>,
18387    ) {
18388        let mut to_fold = Vec::new();
18389        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18390        let selections = self.selections.all_adjusted(cx);
18391
18392        for selection in selections {
18393            let range = selection.range().sorted();
18394            let buffer_start_row = range.start.row;
18395
18396            if range.start.row != range.end.row {
18397                let mut found = false;
18398                for row in range.start.row..=range.end.row {
18399                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18400                        found = true;
18401                        to_fold.push(crease);
18402                    }
18403                }
18404                if found {
18405                    continue;
18406                }
18407            }
18408
18409            for row in (0..=range.start.row).rev() {
18410                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18411                    if crease.range().end.row >= buffer_start_row {
18412                        to_fold.push(crease);
18413                    } else {
18414                        break;
18415                    }
18416                }
18417            }
18418        }
18419
18420        self.fold_creases(to_fold, true, window, cx);
18421    }
18422
18423    pub fn fold_at(
18424        &mut self,
18425        buffer_row: MultiBufferRow,
18426        window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18430
18431        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18432            let autoscroll = self
18433                .selections
18434                .all::<Point>(cx)
18435                .iter()
18436                .any(|selection| crease.range().overlaps(&selection.range()));
18437
18438            self.fold_creases(vec![crease], autoscroll, window, cx);
18439        }
18440    }
18441
18442    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18443        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18444            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18445            let buffer = display_map.buffer_snapshot();
18446            let selections = self.selections.all::<Point>(cx);
18447            let ranges = selections
18448                .iter()
18449                .map(|s| {
18450                    let range = s.display_range(&display_map).sorted();
18451                    let mut start = range.start.to_point(&display_map);
18452                    let mut end = range.end.to_point(&display_map);
18453                    start.column = 0;
18454                    end.column = buffer.line_len(MultiBufferRow(end.row));
18455                    start..end
18456                })
18457                .collect::<Vec<_>>();
18458
18459            self.unfold_ranges(&ranges, true, true, cx);
18460        } else {
18461            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18462            let buffer_ids = self
18463                .selections
18464                .disjoint_anchor_ranges()
18465                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18466                .collect::<HashSet<_>>();
18467            for buffer_id in buffer_ids {
18468                self.unfold_buffer(buffer_id, cx);
18469            }
18470        }
18471    }
18472
18473    pub fn unfold_recursive(
18474        &mut self,
18475        _: &UnfoldRecursive,
18476        _window: &mut Window,
18477        cx: &mut Context<Self>,
18478    ) {
18479        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18480        let selections = self.selections.all::<Point>(cx);
18481        let ranges = selections
18482            .iter()
18483            .map(|s| {
18484                let mut range = s.display_range(&display_map).sorted();
18485                *range.start.column_mut() = 0;
18486                *range.end.column_mut() = display_map.line_len(range.end.row());
18487                let start = range.start.to_point(&display_map);
18488                let end = range.end.to_point(&display_map);
18489                start..end
18490            })
18491            .collect::<Vec<_>>();
18492
18493        self.unfold_ranges(&ranges, true, true, cx);
18494    }
18495
18496    pub fn unfold_at(
18497        &mut self,
18498        buffer_row: MultiBufferRow,
18499        _window: &mut Window,
18500        cx: &mut Context<Self>,
18501    ) {
18502        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18503
18504        let intersection_range = Point::new(buffer_row.0, 0)
18505            ..Point::new(
18506                buffer_row.0,
18507                display_map.buffer_snapshot().line_len(buffer_row),
18508            );
18509
18510        let autoscroll = self
18511            .selections
18512            .all::<Point>(cx)
18513            .iter()
18514            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18515
18516        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18517    }
18518
18519    pub fn unfold_all(
18520        &mut self,
18521        _: &actions::UnfoldAll,
18522        _window: &mut Window,
18523        cx: &mut Context<Self>,
18524    ) {
18525        if self.buffer.read(cx).is_singleton() {
18526            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18527            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18528        } else {
18529            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18530                editor
18531                    .update(cx, |editor, cx| {
18532                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18533                            editor.unfold_buffer(buffer_id, cx);
18534                        }
18535                    })
18536                    .ok();
18537            });
18538        }
18539    }
18540
18541    pub fn fold_selected_ranges(
18542        &mut self,
18543        _: &FoldSelectedRanges,
18544        window: &mut Window,
18545        cx: &mut Context<Self>,
18546    ) {
18547        let selections = self.selections.all_adjusted(cx);
18548        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18549        let ranges = selections
18550            .into_iter()
18551            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18552            .collect::<Vec<_>>();
18553        self.fold_creases(ranges, true, window, cx);
18554    }
18555
18556    pub fn fold_ranges<T: ToOffset + Clone>(
18557        &mut self,
18558        ranges: Vec<Range<T>>,
18559        auto_scroll: bool,
18560        window: &mut Window,
18561        cx: &mut Context<Self>,
18562    ) {
18563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18564        let ranges = ranges
18565            .into_iter()
18566            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18567            .collect::<Vec<_>>();
18568        self.fold_creases(ranges, auto_scroll, window, cx);
18569    }
18570
18571    pub fn fold_creases<T: ToOffset + Clone>(
18572        &mut self,
18573        creases: Vec<Crease<T>>,
18574        auto_scroll: bool,
18575        _window: &mut Window,
18576        cx: &mut Context<Self>,
18577    ) {
18578        if creases.is_empty() {
18579            return;
18580        }
18581
18582        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18583
18584        if auto_scroll {
18585            self.request_autoscroll(Autoscroll::fit(), cx);
18586        }
18587
18588        cx.notify();
18589
18590        self.scrollbar_marker_state.dirty = true;
18591        self.folds_did_change(cx);
18592    }
18593
18594    /// Removes any folds whose ranges intersect any of the given ranges.
18595    pub fn unfold_ranges<T: ToOffset + Clone>(
18596        &mut self,
18597        ranges: &[Range<T>],
18598        inclusive: bool,
18599        auto_scroll: bool,
18600        cx: &mut Context<Self>,
18601    ) {
18602        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18603            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18604        });
18605        self.folds_did_change(cx);
18606    }
18607
18608    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18609        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18610            return;
18611        }
18612        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18613        self.display_map.update(cx, |display_map, cx| {
18614            display_map.fold_buffers([buffer_id], cx)
18615        });
18616        cx.emit(EditorEvent::BufferFoldToggled {
18617            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18618            folded: true,
18619        });
18620        cx.notify();
18621    }
18622
18623    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18624        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18625            return;
18626        }
18627        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18628        self.display_map.update(cx, |display_map, cx| {
18629            display_map.unfold_buffers([buffer_id], cx);
18630        });
18631        cx.emit(EditorEvent::BufferFoldToggled {
18632            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18633            folded: false,
18634        });
18635        cx.notify();
18636    }
18637
18638    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18639        self.display_map.read(cx).is_buffer_folded(buffer)
18640    }
18641
18642    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18643        self.display_map.read(cx).folded_buffers()
18644    }
18645
18646    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18647        self.display_map.update(cx, |display_map, cx| {
18648            display_map.disable_header_for_buffer(buffer_id, cx);
18649        });
18650        cx.notify();
18651    }
18652
18653    /// Removes any folds with the given ranges.
18654    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18655        &mut self,
18656        ranges: &[Range<T>],
18657        type_id: TypeId,
18658        auto_scroll: bool,
18659        cx: &mut Context<Self>,
18660    ) {
18661        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18662            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18663        });
18664        self.folds_did_change(cx);
18665    }
18666
18667    fn remove_folds_with<T: ToOffset + Clone>(
18668        &mut self,
18669        ranges: &[Range<T>],
18670        auto_scroll: bool,
18671        cx: &mut Context<Self>,
18672        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18673    ) {
18674        if ranges.is_empty() {
18675            return;
18676        }
18677
18678        let mut buffers_affected = HashSet::default();
18679        let multi_buffer = self.buffer().read(cx);
18680        for range in ranges {
18681            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18682                buffers_affected.insert(buffer.read(cx).remote_id());
18683            };
18684        }
18685
18686        self.display_map.update(cx, update);
18687
18688        if auto_scroll {
18689            self.request_autoscroll(Autoscroll::fit(), cx);
18690        }
18691
18692        cx.notify();
18693        self.scrollbar_marker_state.dirty = true;
18694        self.active_indent_guides_state.dirty = true;
18695    }
18696
18697    pub fn update_renderer_widths(
18698        &mut self,
18699        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18700        cx: &mut Context<Self>,
18701    ) -> bool {
18702        self.display_map
18703            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18704    }
18705
18706    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18707        self.display_map.read(cx).fold_placeholder.clone()
18708    }
18709
18710    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18711        self.buffer.update(cx, |buffer, cx| {
18712            buffer.set_all_diff_hunks_expanded(cx);
18713        });
18714    }
18715
18716    pub fn expand_all_diff_hunks(
18717        &mut self,
18718        _: &ExpandAllDiffHunks,
18719        _window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) {
18722        self.buffer.update(cx, |buffer, cx| {
18723            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18724        });
18725    }
18726
18727    pub fn toggle_selected_diff_hunks(
18728        &mut self,
18729        _: &ToggleSelectedDiffHunks,
18730        _window: &mut Window,
18731        cx: &mut Context<Self>,
18732    ) {
18733        let ranges: Vec<_> = self
18734            .selections
18735            .disjoint_anchors()
18736            .iter()
18737            .map(|s| s.range())
18738            .collect();
18739        self.toggle_diff_hunks_in_ranges(ranges, cx);
18740    }
18741
18742    pub fn diff_hunks_in_ranges<'a>(
18743        &'a self,
18744        ranges: &'a [Range<Anchor>],
18745        buffer: &'a MultiBufferSnapshot,
18746    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18747        ranges.iter().flat_map(move |range| {
18748            let end_excerpt_id = range.end.excerpt_id;
18749            let range = range.to_point(buffer);
18750            let mut peek_end = range.end;
18751            if range.end.row < buffer.max_row().0 {
18752                peek_end = Point::new(range.end.row + 1, 0);
18753            }
18754            buffer
18755                .diff_hunks_in_range(range.start..peek_end)
18756                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18757        })
18758    }
18759
18760    pub fn has_stageable_diff_hunks_in_ranges(
18761        &self,
18762        ranges: &[Range<Anchor>],
18763        snapshot: &MultiBufferSnapshot,
18764    ) -> bool {
18765        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18766        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18767    }
18768
18769    pub fn toggle_staged_selected_diff_hunks(
18770        &mut self,
18771        _: &::git::ToggleStaged,
18772        _: &mut Window,
18773        cx: &mut Context<Self>,
18774    ) {
18775        let snapshot = self.buffer.read(cx).snapshot(cx);
18776        let ranges: Vec<_> = self
18777            .selections
18778            .disjoint_anchors()
18779            .iter()
18780            .map(|s| s.range())
18781            .collect();
18782        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18783        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18784    }
18785
18786    pub fn set_render_diff_hunk_controls(
18787        &mut self,
18788        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18789        cx: &mut Context<Self>,
18790    ) {
18791        self.render_diff_hunk_controls = render_diff_hunk_controls;
18792        cx.notify();
18793    }
18794
18795    pub fn stage_and_next(
18796        &mut self,
18797        _: &::git::StageAndNext,
18798        window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        self.do_stage_or_unstage_and_next(true, window, cx);
18802    }
18803
18804    pub fn unstage_and_next(
18805        &mut self,
18806        _: &::git::UnstageAndNext,
18807        window: &mut Window,
18808        cx: &mut Context<Self>,
18809    ) {
18810        self.do_stage_or_unstage_and_next(false, window, cx);
18811    }
18812
18813    pub fn stage_or_unstage_diff_hunks(
18814        &mut self,
18815        stage: bool,
18816        ranges: Vec<Range<Anchor>>,
18817        cx: &mut Context<Self>,
18818    ) {
18819        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18820        cx.spawn(async move |this, cx| {
18821            task.await?;
18822            this.update(cx, |this, cx| {
18823                let snapshot = this.buffer.read(cx).snapshot(cx);
18824                let chunk_by = this
18825                    .diff_hunks_in_ranges(&ranges, &snapshot)
18826                    .chunk_by(|hunk| hunk.buffer_id);
18827                for (buffer_id, hunks) in &chunk_by {
18828                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18829                }
18830            })
18831        })
18832        .detach_and_log_err(cx);
18833    }
18834
18835    fn save_buffers_for_ranges_if_needed(
18836        &mut self,
18837        ranges: &[Range<Anchor>],
18838        cx: &mut Context<Editor>,
18839    ) -> Task<Result<()>> {
18840        let multibuffer = self.buffer.read(cx);
18841        let snapshot = multibuffer.read(cx);
18842        let buffer_ids: HashSet<_> = ranges
18843            .iter()
18844            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18845            .collect();
18846        drop(snapshot);
18847
18848        let mut buffers = HashSet::default();
18849        for buffer_id in buffer_ids {
18850            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18851                let buffer = buffer_entity.read(cx);
18852                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18853                {
18854                    buffers.insert(buffer_entity);
18855                }
18856            }
18857        }
18858
18859        if let Some(project) = &self.project {
18860            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18861        } else {
18862            Task::ready(Ok(()))
18863        }
18864    }
18865
18866    fn do_stage_or_unstage_and_next(
18867        &mut self,
18868        stage: bool,
18869        window: &mut Window,
18870        cx: &mut Context<Self>,
18871    ) {
18872        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18873
18874        if ranges.iter().any(|range| range.start != range.end) {
18875            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18876            return;
18877        }
18878
18879        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18880        let snapshot = self.snapshot(window, cx);
18881        let position = self.selections.newest::<Point>(cx).head();
18882        let mut row = snapshot
18883            .buffer_snapshot()
18884            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18885            .find(|hunk| hunk.row_range.start.0 > position.row)
18886            .map(|hunk| hunk.row_range.start);
18887
18888        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18889        // Outside of the project diff editor, wrap around to the beginning.
18890        if !all_diff_hunks_expanded {
18891            row = row.or_else(|| {
18892                snapshot
18893                    .buffer_snapshot()
18894                    .diff_hunks_in_range(Point::zero()..position)
18895                    .find(|hunk| hunk.row_range.end.0 < position.row)
18896                    .map(|hunk| hunk.row_range.start)
18897            });
18898        }
18899
18900        if let Some(row) = row {
18901            let destination = Point::new(row.0, 0);
18902            let autoscroll = Autoscroll::center();
18903
18904            self.unfold_ranges(&[destination..destination], false, false, cx);
18905            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18906                s.select_ranges([destination..destination]);
18907            });
18908        }
18909    }
18910
18911    fn do_stage_or_unstage(
18912        &self,
18913        stage: bool,
18914        buffer_id: BufferId,
18915        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18916        cx: &mut App,
18917    ) -> Option<()> {
18918        let project = self.project()?;
18919        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18920        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18921        let buffer_snapshot = buffer.read(cx).snapshot();
18922        let file_exists = buffer_snapshot
18923            .file()
18924            .is_some_and(|file| file.disk_state().exists());
18925        diff.update(cx, |diff, cx| {
18926            diff.stage_or_unstage_hunks(
18927                stage,
18928                &hunks
18929                    .map(|hunk| buffer_diff::DiffHunk {
18930                        buffer_range: hunk.buffer_range,
18931                        diff_base_byte_range: hunk.diff_base_byte_range,
18932                        secondary_status: hunk.secondary_status,
18933                        range: Point::zero()..Point::zero(), // unused
18934                    })
18935                    .collect::<Vec<_>>(),
18936                &buffer_snapshot,
18937                file_exists,
18938                cx,
18939            )
18940        });
18941        None
18942    }
18943
18944    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18945        let ranges: Vec<_> = self
18946            .selections
18947            .disjoint_anchors()
18948            .iter()
18949            .map(|s| s.range())
18950            .collect();
18951        self.buffer
18952            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18953    }
18954
18955    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18956        self.buffer.update(cx, |buffer, cx| {
18957            let ranges = vec![Anchor::min()..Anchor::max()];
18958            if !buffer.all_diff_hunks_expanded()
18959                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18960            {
18961                buffer.collapse_diff_hunks(ranges, cx);
18962                true
18963            } else {
18964                false
18965            }
18966        })
18967    }
18968
18969    fn toggle_diff_hunks_in_ranges(
18970        &mut self,
18971        ranges: Vec<Range<Anchor>>,
18972        cx: &mut Context<Editor>,
18973    ) {
18974        self.buffer.update(cx, |buffer, cx| {
18975            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18976            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18977        })
18978    }
18979
18980    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18981        self.buffer.update(cx, |buffer, cx| {
18982            let snapshot = buffer.snapshot(cx);
18983            let excerpt_id = range.end.excerpt_id;
18984            let point_range = range.to_point(&snapshot);
18985            let expand = !buffer.single_hunk_is_expanded(range, cx);
18986            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18987        })
18988    }
18989
18990    pub(crate) fn apply_all_diff_hunks(
18991        &mut self,
18992        _: &ApplyAllDiffHunks,
18993        window: &mut Window,
18994        cx: &mut Context<Self>,
18995    ) {
18996        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18997
18998        let buffers = self.buffer.read(cx).all_buffers();
18999        for branch_buffer in buffers {
19000            branch_buffer.update(cx, |branch_buffer, cx| {
19001                branch_buffer.merge_into_base(Vec::new(), cx);
19002            });
19003        }
19004
19005        if let Some(project) = self.project.clone() {
19006            self.save(
19007                SaveOptions {
19008                    format: true,
19009                    autosave: false,
19010                },
19011                project,
19012                window,
19013                cx,
19014            )
19015            .detach_and_log_err(cx);
19016        }
19017    }
19018
19019    pub(crate) fn apply_selected_diff_hunks(
19020        &mut self,
19021        _: &ApplyDiffHunk,
19022        window: &mut Window,
19023        cx: &mut Context<Self>,
19024    ) {
19025        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19026        let snapshot = self.snapshot(window, cx);
19027        let hunks = snapshot.hunks_for_ranges(
19028            self.selections
19029                .all(cx)
19030                .into_iter()
19031                .map(|selection| selection.range()),
19032        );
19033        let mut ranges_by_buffer = HashMap::default();
19034        self.transact(window, cx, |editor, _window, cx| {
19035            for hunk in hunks {
19036                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19037                    ranges_by_buffer
19038                        .entry(buffer.clone())
19039                        .or_insert_with(Vec::new)
19040                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19041                }
19042            }
19043
19044            for (buffer, ranges) in ranges_by_buffer {
19045                buffer.update(cx, |buffer, cx| {
19046                    buffer.merge_into_base(ranges, cx);
19047                });
19048            }
19049        });
19050
19051        if let Some(project) = self.project.clone() {
19052            self.save(
19053                SaveOptions {
19054                    format: true,
19055                    autosave: false,
19056                },
19057                project,
19058                window,
19059                cx,
19060            )
19061            .detach_and_log_err(cx);
19062        }
19063    }
19064
19065    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19066        if hovered != self.gutter_hovered {
19067            self.gutter_hovered = hovered;
19068            cx.notify();
19069        }
19070    }
19071
19072    pub fn insert_blocks(
19073        &mut self,
19074        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19075        autoscroll: Option<Autoscroll>,
19076        cx: &mut Context<Self>,
19077    ) -> Vec<CustomBlockId> {
19078        let blocks = self
19079            .display_map
19080            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19081        if let Some(autoscroll) = autoscroll {
19082            self.request_autoscroll(autoscroll, cx);
19083        }
19084        cx.notify();
19085        blocks
19086    }
19087
19088    pub fn resize_blocks(
19089        &mut self,
19090        heights: HashMap<CustomBlockId, u32>,
19091        autoscroll: Option<Autoscroll>,
19092        cx: &mut Context<Self>,
19093    ) {
19094        self.display_map
19095            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19096        if let Some(autoscroll) = autoscroll {
19097            self.request_autoscroll(autoscroll, cx);
19098        }
19099        cx.notify();
19100    }
19101
19102    pub fn replace_blocks(
19103        &mut self,
19104        renderers: HashMap<CustomBlockId, RenderBlock>,
19105        autoscroll: Option<Autoscroll>,
19106        cx: &mut Context<Self>,
19107    ) {
19108        self.display_map
19109            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19110        if let Some(autoscroll) = autoscroll {
19111            self.request_autoscroll(autoscroll, cx);
19112        }
19113        cx.notify();
19114    }
19115
19116    pub fn remove_blocks(
19117        &mut self,
19118        block_ids: HashSet<CustomBlockId>,
19119        autoscroll: Option<Autoscroll>,
19120        cx: &mut Context<Self>,
19121    ) {
19122        self.display_map.update(cx, |display_map, cx| {
19123            display_map.remove_blocks(block_ids, cx)
19124        });
19125        if let Some(autoscroll) = autoscroll {
19126            self.request_autoscroll(autoscroll, cx);
19127        }
19128        cx.notify();
19129    }
19130
19131    pub fn row_for_block(
19132        &self,
19133        block_id: CustomBlockId,
19134        cx: &mut Context<Self>,
19135    ) -> Option<DisplayRow> {
19136        self.display_map
19137            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19138    }
19139
19140    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19141        self.focused_block = Some(focused_block);
19142    }
19143
19144    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19145        self.focused_block.take()
19146    }
19147
19148    pub fn insert_creases(
19149        &mut self,
19150        creases: impl IntoIterator<Item = Crease<Anchor>>,
19151        cx: &mut Context<Self>,
19152    ) -> Vec<CreaseId> {
19153        self.display_map
19154            .update(cx, |map, cx| map.insert_creases(creases, cx))
19155    }
19156
19157    pub fn remove_creases(
19158        &mut self,
19159        ids: impl IntoIterator<Item = CreaseId>,
19160        cx: &mut Context<Self>,
19161    ) -> Vec<(CreaseId, Range<Anchor>)> {
19162        self.display_map
19163            .update(cx, |map, cx| map.remove_creases(ids, cx))
19164    }
19165
19166    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19167        self.display_map
19168            .update(cx, |map, cx| map.snapshot(cx))
19169            .longest_row()
19170    }
19171
19172    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19173        self.display_map
19174            .update(cx, |map, cx| map.snapshot(cx))
19175            .max_point()
19176    }
19177
19178    pub fn text(&self, cx: &App) -> String {
19179        self.buffer.read(cx).read(cx).text()
19180    }
19181
19182    pub fn is_empty(&self, cx: &App) -> bool {
19183        self.buffer.read(cx).read(cx).is_empty()
19184    }
19185
19186    pub fn text_option(&self, cx: &App) -> Option<String> {
19187        let text = self.text(cx);
19188        let text = text.trim();
19189
19190        if text.is_empty() {
19191            return None;
19192        }
19193
19194        Some(text.to_string())
19195    }
19196
19197    pub fn set_text(
19198        &mut self,
19199        text: impl Into<Arc<str>>,
19200        window: &mut Window,
19201        cx: &mut Context<Self>,
19202    ) {
19203        self.transact(window, cx, |this, _, cx| {
19204            this.buffer
19205                .read(cx)
19206                .as_singleton()
19207                .expect("you can only call set_text on editors for singleton buffers")
19208                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19209        });
19210    }
19211
19212    pub fn display_text(&self, cx: &mut App) -> String {
19213        self.display_map
19214            .update(cx, |map, cx| map.snapshot(cx))
19215            .text()
19216    }
19217
19218    fn create_minimap(
19219        &self,
19220        minimap_settings: MinimapSettings,
19221        window: &mut Window,
19222        cx: &mut Context<Self>,
19223    ) -> Option<Entity<Self>> {
19224        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19225            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19226    }
19227
19228    fn initialize_new_minimap(
19229        &self,
19230        minimap_settings: MinimapSettings,
19231        window: &mut Window,
19232        cx: &mut Context<Self>,
19233    ) -> Entity<Self> {
19234        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19235
19236        let mut minimap = Editor::new_internal(
19237            EditorMode::Minimap {
19238                parent: cx.weak_entity(),
19239            },
19240            self.buffer.clone(),
19241            None,
19242            Some(self.display_map.clone()),
19243            window,
19244            cx,
19245        );
19246        minimap.scroll_manager.clone_state(&self.scroll_manager);
19247        minimap.set_text_style_refinement(TextStyleRefinement {
19248            font_size: Some(MINIMAP_FONT_SIZE),
19249            font_weight: Some(MINIMAP_FONT_WEIGHT),
19250            ..Default::default()
19251        });
19252        minimap.update_minimap_configuration(minimap_settings, cx);
19253        cx.new(|_| minimap)
19254    }
19255
19256    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19257        let current_line_highlight = minimap_settings
19258            .current_line_highlight
19259            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19260        self.set_current_line_highlight(Some(current_line_highlight));
19261    }
19262
19263    pub fn minimap(&self) -> Option<&Entity<Self>> {
19264        self.minimap
19265            .as_ref()
19266            .filter(|_| self.minimap_visibility.visible())
19267    }
19268
19269    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19270        let mut wrap_guides = smallvec![];
19271
19272        if self.show_wrap_guides == Some(false) {
19273            return wrap_guides;
19274        }
19275
19276        let settings = self.buffer.read(cx).language_settings(cx);
19277        if settings.show_wrap_guides {
19278            match self.soft_wrap_mode(cx) {
19279                SoftWrap::Column(soft_wrap) => {
19280                    wrap_guides.push((soft_wrap as usize, true));
19281                }
19282                SoftWrap::Bounded(soft_wrap) => {
19283                    wrap_guides.push((soft_wrap as usize, true));
19284                }
19285                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19286            }
19287            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19288        }
19289
19290        wrap_guides
19291    }
19292
19293    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19294        let settings = self.buffer.read(cx).language_settings(cx);
19295        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19296        match mode {
19297            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19298                SoftWrap::None
19299            }
19300            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19301            language_settings::SoftWrap::PreferredLineLength => {
19302                SoftWrap::Column(settings.preferred_line_length)
19303            }
19304            language_settings::SoftWrap::Bounded => {
19305                SoftWrap::Bounded(settings.preferred_line_length)
19306            }
19307        }
19308    }
19309
19310    pub fn set_soft_wrap_mode(
19311        &mut self,
19312        mode: language_settings::SoftWrap,
19313
19314        cx: &mut Context<Self>,
19315    ) {
19316        self.soft_wrap_mode_override = Some(mode);
19317        cx.notify();
19318    }
19319
19320    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19321        self.hard_wrap = hard_wrap;
19322        cx.notify();
19323    }
19324
19325    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19326        self.text_style_refinement = Some(style);
19327    }
19328
19329    /// called by the Element so we know what style we were most recently rendered with.
19330    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19331        // We intentionally do not inform the display map about the minimap style
19332        // so that wrapping is not recalculated and stays consistent for the editor
19333        // and its linked minimap.
19334        if !self.mode.is_minimap() {
19335            let font = style.text.font();
19336            let font_size = style.text.font_size.to_pixels(window.rem_size());
19337            let display_map = self
19338                .placeholder_display_map
19339                .as_ref()
19340                .filter(|_| self.is_empty(cx))
19341                .unwrap_or(&self.display_map);
19342
19343            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19344        }
19345        self.style = Some(style);
19346    }
19347
19348    pub fn style(&self) -> Option<&EditorStyle> {
19349        self.style.as_ref()
19350    }
19351
19352    // Called by the element. This method is not designed to be called outside of the editor
19353    // element's layout code because it does not notify when rewrapping is computed synchronously.
19354    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19355        if self.is_empty(cx) {
19356            self.placeholder_display_map
19357                .as_ref()
19358                .map_or(false, |display_map| {
19359                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19360                })
19361        } else {
19362            self.display_map
19363                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19364        }
19365    }
19366
19367    pub fn set_soft_wrap(&mut self) {
19368        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19369    }
19370
19371    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19372        if self.soft_wrap_mode_override.is_some() {
19373            self.soft_wrap_mode_override.take();
19374        } else {
19375            let soft_wrap = match self.soft_wrap_mode(cx) {
19376                SoftWrap::GitDiff => return,
19377                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19378                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19379                    language_settings::SoftWrap::None
19380                }
19381            };
19382            self.soft_wrap_mode_override = Some(soft_wrap);
19383        }
19384        cx.notify();
19385    }
19386
19387    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19388        let Some(workspace) = self.workspace() else {
19389            return;
19390        };
19391        let fs = workspace.read(cx).app_state().fs.clone();
19392        let current_show = TabBarSettings::get_global(cx).show;
19393        update_settings_file(fs, cx, move |setting, _| {
19394            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19395        });
19396    }
19397
19398    pub fn toggle_indent_guides(
19399        &mut self,
19400        _: &ToggleIndentGuides,
19401        _: &mut Window,
19402        cx: &mut Context<Self>,
19403    ) {
19404        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19405            self.buffer
19406                .read(cx)
19407                .language_settings(cx)
19408                .indent_guides
19409                .enabled
19410        });
19411        self.show_indent_guides = Some(!currently_enabled);
19412        cx.notify();
19413    }
19414
19415    fn should_show_indent_guides(&self) -> Option<bool> {
19416        self.show_indent_guides
19417    }
19418
19419    pub fn toggle_line_numbers(
19420        &mut self,
19421        _: &ToggleLineNumbers,
19422        _: &mut Window,
19423        cx: &mut Context<Self>,
19424    ) {
19425        let mut editor_settings = EditorSettings::get_global(cx).clone();
19426        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19427        EditorSettings::override_global(editor_settings, cx);
19428    }
19429
19430    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19431        if let Some(show_line_numbers) = self.show_line_numbers {
19432            return show_line_numbers;
19433        }
19434        EditorSettings::get_global(cx).gutter.line_numbers
19435    }
19436
19437    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19438        self.use_relative_line_numbers
19439            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19440    }
19441
19442    pub fn toggle_relative_line_numbers(
19443        &mut self,
19444        _: &ToggleRelativeLineNumbers,
19445        _: &mut Window,
19446        cx: &mut Context<Self>,
19447    ) {
19448        let is_relative = self.should_use_relative_line_numbers(cx);
19449        self.set_relative_line_number(Some(!is_relative), cx)
19450    }
19451
19452    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19453        self.use_relative_line_numbers = is_relative;
19454        cx.notify();
19455    }
19456
19457    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19458        self.show_gutter = show_gutter;
19459        cx.notify();
19460    }
19461
19462    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19463        self.show_scrollbars = ScrollbarAxes {
19464            horizontal: show,
19465            vertical: show,
19466        };
19467        cx.notify();
19468    }
19469
19470    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19471        self.show_scrollbars.vertical = show;
19472        cx.notify();
19473    }
19474
19475    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19476        self.show_scrollbars.horizontal = show;
19477        cx.notify();
19478    }
19479
19480    pub fn set_minimap_visibility(
19481        &mut self,
19482        minimap_visibility: MinimapVisibility,
19483        window: &mut Window,
19484        cx: &mut Context<Self>,
19485    ) {
19486        if self.minimap_visibility != minimap_visibility {
19487            if minimap_visibility.visible() && self.minimap.is_none() {
19488                let minimap_settings = EditorSettings::get_global(cx).minimap;
19489                self.minimap =
19490                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19491            }
19492            self.minimap_visibility = minimap_visibility;
19493            cx.notify();
19494        }
19495    }
19496
19497    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19498        self.set_show_scrollbars(false, cx);
19499        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19500    }
19501
19502    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19503        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19504    }
19505
19506    /// Normally the text in full mode and auto height editors is padded on the
19507    /// left side by roughly half a character width for improved hit testing.
19508    ///
19509    /// Use this method to disable this for cases where this is not wanted (e.g.
19510    /// if you want to align the editor text with some other text above or below)
19511    /// or if you want to add this padding to single-line editors.
19512    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19513        self.offset_content = offset_content;
19514        cx.notify();
19515    }
19516
19517    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19518        self.show_line_numbers = Some(show_line_numbers);
19519        cx.notify();
19520    }
19521
19522    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19523        self.disable_expand_excerpt_buttons = true;
19524        cx.notify();
19525    }
19526
19527    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19528        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19529        cx.notify();
19530    }
19531
19532    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19533        self.show_code_actions = Some(show_code_actions);
19534        cx.notify();
19535    }
19536
19537    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19538        self.show_runnables = Some(show_runnables);
19539        cx.notify();
19540    }
19541
19542    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19543        self.show_breakpoints = Some(show_breakpoints);
19544        cx.notify();
19545    }
19546
19547    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19548        if self.display_map.read(cx).masked != masked {
19549            self.display_map.update(cx, |map, _| map.masked = masked);
19550        }
19551        cx.notify()
19552    }
19553
19554    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19555        self.show_wrap_guides = Some(show_wrap_guides);
19556        cx.notify();
19557    }
19558
19559    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19560        self.show_indent_guides = Some(show_indent_guides);
19561        cx.notify();
19562    }
19563
19564    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19565        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19566            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19567                && let Some(dir) = file.abs_path(cx).parent()
19568            {
19569                return Some(dir.to_owned());
19570            }
19571        }
19572
19573        None
19574    }
19575
19576    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19577        self.active_excerpt(cx)?
19578            .1
19579            .read(cx)
19580            .file()
19581            .and_then(|f| f.as_local())
19582    }
19583
19584    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19585        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19586            let buffer = buffer.read(cx);
19587            if let Some(project_path) = buffer.project_path(cx) {
19588                let project = self.project()?.read(cx);
19589                project.absolute_path(&project_path, cx)
19590            } else {
19591                buffer
19592                    .file()
19593                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19594            }
19595        })
19596    }
19597
19598    pub fn reveal_in_finder(
19599        &mut self,
19600        _: &RevealInFileManager,
19601        _window: &mut Window,
19602        cx: &mut Context<Self>,
19603    ) {
19604        if let Some(target) = self.target_file(cx) {
19605            cx.reveal_path(&target.abs_path(cx));
19606        }
19607    }
19608
19609    pub fn copy_path(
19610        &mut self,
19611        _: &zed_actions::workspace::CopyPath,
19612        _window: &mut Window,
19613        cx: &mut Context<Self>,
19614    ) {
19615        if let Some(path) = self.target_file_abs_path(cx)
19616            && let Some(path) = path.to_str()
19617        {
19618            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19619        } else {
19620            cx.propagate();
19621        }
19622    }
19623
19624    pub fn copy_relative_path(
19625        &mut self,
19626        _: &zed_actions::workspace::CopyRelativePath,
19627        _window: &mut Window,
19628        cx: &mut Context<Self>,
19629    ) {
19630        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19631            let project = self.project()?.read(cx);
19632            let path = buffer.read(cx).file()?.path();
19633            let path = path.display(project.path_style(cx));
19634            Some(path)
19635        }) {
19636            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19637        } else {
19638            cx.propagate();
19639        }
19640    }
19641
19642    /// Returns the project path for the editor's buffer, if any buffer is
19643    /// opened in the editor.
19644    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19645        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19646            buffer.read(cx).project_path(cx)
19647        } else {
19648            None
19649        }
19650    }
19651
19652    // Returns true if the editor handled a go-to-line request
19653    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19654        maybe!({
19655            let breakpoint_store = self.breakpoint_store.as_ref()?;
19656
19657            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19658            else {
19659                self.clear_row_highlights::<ActiveDebugLine>();
19660                return None;
19661            };
19662
19663            let position = active_stack_frame.position;
19664            let buffer_id = position.buffer_id?;
19665            let snapshot = self
19666                .project
19667                .as_ref()?
19668                .read(cx)
19669                .buffer_for_id(buffer_id, cx)?
19670                .read(cx)
19671                .snapshot();
19672
19673            let mut handled = false;
19674            for (id, ExcerptRange { context, .. }) in
19675                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19676            {
19677                if context.start.cmp(&position, &snapshot).is_ge()
19678                    || context.end.cmp(&position, &snapshot).is_lt()
19679                {
19680                    continue;
19681                }
19682                let snapshot = self.buffer.read(cx).snapshot(cx);
19683                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19684
19685                handled = true;
19686                self.clear_row_highlights::<ActiveDebugLine>();
19687
19688                self.go_to_line::<ActiveDebugLine>(
19689                    multibuffer_anchor,
19690                    Some(cx.theme().colors().editor_debugger_active_line_background),
19691                    window,
19692                    cx,
19693                );
19694
19695                cx.notify();
19696            }
19697
19698            handled.then_some(())
19699        })
19700        .is_some()
19701    }
19702
19703    pub fn copy_file_name_without_extension(
19704        &mut self,
19705        _: &CopyFileNameWithoutExtension,
19706        _: &mut Window,
19707        cx: &mut Context<Self>,
19708    ) {
19709        if let Some(file) = self.target_file(cx)
19710            && let Some(file_stem) = file.path().file_stem()
19711        {
19712            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19713        }
19714    }
19715
19716    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19717        if let Some(file) = self.target_file(cx)
19718            && let Some(name) = file.path().file_name()
19719        {
19720            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19721        }
19722    }
19723
19724    pub fn toggle_git_blame(
19725        &mut self,
19726        _: &::git::Blame,
19727        window: &mut Window,
19728        cx: &mut Context<Self>,
19729    ) {
19730        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19731
19732        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19733            self.start_git_blame(true, window, cx);
19734        }
19735
19736        cx.notify();
19737    }
19738
19739    pub fn toggle_git_blame_inline(
19740        &mut self,
19741        _: &ToggleGitBlameInline,
19742        window: &mut Window,
19743        cx: &mut Context<Self>,
19744    ) {
19745        self.toggle_git_blame_inline_internal(true, window, cx);
19746        cx.notify();
19747    }
19748
19749    pub fn open_git_blame_commit(
19750        &mut self,
19751        _: &OpenGitBlameCommit,
19752        window: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        self.open_git_blame_commit_internal(window, cx);
19756    }
19757
19758    fn open_git_blame_commit_internal(
19759        &mut self,
19760        window: &mut Window,
19761        cx: &mut Context<Self>,
19762    ) -> Option<()> {
19763        let blame = self.blame.as_ref()?;
19764        let snapshot = self.snapshot(window, cx);
19765        let cursor = self.selections.newest::<Point>(cx).head();
19766        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19767        let (_, blame_entry) = blame
19768            .update(cx, |blame, cx| {
19769                blame
19770                    .blame_for_rows(
19771                        &[RowInfo {
19772                            buffer_id: Some(buffer.remote_id()),
19773                            buffer_row: Some(point.row),
19774                            ..Default::default()
19775                        }],
19776                        cx,
19777                    )
19778                    .next()
19779            })
19780            .flatten()?;
19781        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19782        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19783        let workspace = self.workspace()?.downgrade();
19784        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19785        None
19786    }
19787
19788    pub fn git_blame_inline_enabled(&self) -> bool {
19789        self.git_blame_inline_enabled
19790    }
19791
19792    pub fn toggle_selection_menu(
19793        &mut self,
19794        _: &ToggleSelectionMenu,
19795        _: &mut Window,
19796        cx: &mut Context<Self>,
19797    ) {
19798        self.show_selection_menu = self
19799            .show_selection_menu
19800            .map(|show_selections_menu| !show_selections_menu)
19801            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19802
19803        cx.notify();
19804    }
19805
19806    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19807        self.show_selection_menu
19808            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19809    }
19810
19811    fn start_git_blame(
19812        &mut self,
19813        user_triggered: bool,
19814        window: &mut Window,
19815        cx: &mut Context<Self>,
19816    ) {
19817        if let Some(project) = self.project() {
19818            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19819                && buffer.read(cx).file().is_none()
19820            {
19821                return;
19822            }
19823
19824            let focused = self.focus_handle(cx).contains_focused(window, cx);
19825
19826            let project = project.clone();
19827            let blame = cx
19828                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19829            self.blame_subscription =
19830                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19831            self.blame = Some(blame);
19832        }
19833    }
19834
19835    fn toggle_git_blame_inline_internal(
19836        &mut self,
19837        user_triggered: bool,
19838        window: &mut Window,
19839        cx: &mut Context<Self>,
19840    ) {
19841        if self.git_blame_inline_enabled {
19842            self.git_blame_inline_enabled = false;
19843            self.show_git_blame_inline = false;
19844            self.show_git_blame_inline_delay_task.take();
19845        } else {
19846            self.git_blame_inline_enabled = true;
19847            self.start_git_blame_inline(user_triggered, window, cx);
19848        }
19849
19850        cx.notify();
19851    }
19852
19853    fn start_git_blame_inline(
19854        &mut self,
19855        user_triggered: bool,
19856        window: &mut Window,
19857        cx: &mut Context<Self>,
19858    ) {
19859        self.start_git_blame(user_triggered, window, cx);
19860
19861        if ProjectSettings::get_global(cx)
19862            .git
19863            .inline_blame_delay()
19864            .is_some()
19865        {
19866            self.start_inline_blame_timer(window, cx);
19867        } else {
19868            self.show_git_blame_inline = true
19869        }
19870    }
19871
19872    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19873        self.blame.as_ref()
19874    }
19875
19876    pub fn show_git_blame_gutter(&self) -> bool {
19877        self.show_git_blame_gutter
19878    }
19879
19880    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19881        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19882    }
19883
19884    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19885        self.show_git_blame_inline
19886            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19887            && !self.newest_selection_head_on_empty_line(cx)
19888            && self.has_blame_entries(cx)
19889    }
19890
19891    fn has_blame_entries(&self, cx: &App) -> bool {
19892        self.blame()
19893            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19894    }
19895
19896    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19897        let cursor_anchor = self.selections.newest_anchor().head();
19898
19899        let snapshot = self.buffer.read(cx).snapshot(cx);
19900        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19901
19902        snapshot.line_len(buffer_row) == 0
19903    }
19904
19905    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19906        let buffer_and_selection = maybe!({
19907            let selection = self.selections.newest::<Point>(cx);
19908            let selection_range = selection.range();
19909
19910            let multi_buffer = self.buffer().read(cx);
19911            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19912            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19913
19914            let (buffer, range, _) = if selection.reversed {
19915                buffer_ranges.first()
19916            } else {
19917                buffer_ranges.last()
19918            }?;
19919
19920            let selection = text::ToPoint::to_point(&range.start, buffer).row
19921                ..text::ToPoint::to_point(&range.end, buffer).row;
19922            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19923        });
19924
19925        let Some((buffer, selection)) = buffer_and_selection else {
19926            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19927        };
19928
19929        let Some(project) = self.project() else {
19930            return Task::ready(Err(anyhow!("editor does not have project")));
19931        };
19932
19933        project.update(cx, |project, cx| {
19934            project.get_permalink_to_line(&buffer, selection, cx)
19935        })
19936    }
19937
19938    pub fn copy_permalink_to_line(
19939        &mut self,
19940        _: &CopyPermalinkToLine,
19941        window: &mut Window,
19942        cx: &mut Context<Self>,
19943    ) {
19944        let permalink_task = self.get_permalink_to_line(cx);
19945        let workspace = self.workspace();
19946
19947        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19948            Ok(permalink) => {
19949                cx.update(|_, cx| {
19950                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19951                })
19952                .ok();
19953            }
19954            Err(err) => {
19955                let message = format!("Failed to copy permalink: {err}");
19956
19957                anyhow::Result::<()>::Err(err).log_err();
19958
19959                if let Some(workspace) = workspace {
19960                    workspace
19961                        .update_in(cx, |workspace, _, cx| {
19962                            struct CopyPermalinkToLine;
19963
19964                            workspace.show_toast(
19965                                Toast::new(
19966                                    NotificationId::unique::<CopyPermalinkToLine>(),
19967                                    message,
19968                                ),
19969                                cx,
19970                            )
19971                        })
19972                        .ok();
19973                }
19974            }
19975        })
19976        .detach();
19977    }
19978
19979    pub fn copy_file_location(
19980        &mut self,
19981        _: &CopyFileLocation,
19982        _: &mut Window,
19983        cx: &mut Context<Self>,
19984    ) {
19985        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19986        if let Some(file) = self.target_file(cx) {
19987            let path = file.path().display(file.path_style(cx));
19988            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19989        }
19990    }
19991
19992    pub fn open_permalink_to_line(
19993        &mut self,
19994        _: &OpenPermalinkToLine,
19995        window: &mut Window,
19996        cx: &mut Context<Self>,
19997    ) {
19998        let permalink_task = self.get_permalink_to_line(cx);
19999        let workspace = self.workspace();
20000
20001        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20002            Ok(permalink) => {
20003                cx.update(|_, cx| {
20004                    cx.open_url(permalink.as_ref());
20005                })
20006                .ok();
20007            }
20008            Err(err) => {
20009                let message = format!("Failed to open permalink: {err}");
20010
20011                anyhow::Result::<()>::Err(err).log_err();
20012
20013                if let Some(workspace) = workspace {
20014                    workspace
20015                        .update(cx, |workspace, cx| {
20016                            struct OpenPermalinkToLine;
20017
20018                            workspace.show_toast(
20019                                Toast::new(
20020                                    NotificationId::unique::<OpenPermalinkToLine>(),
20021                                    message,
20022                                ),
20023                                cx,
20024                            )
20025                        })
20026                        .ok();
20027                }
20028            }
20029        })
20030        .detach();
20031    }
20032
20033    pub fn insert_uuid_v4(
20034        &mut self,
20035        _: &InsertUuidV4,
20036        window: &mut Window,
20037        cx: &mut Context<Self>,
20038    ) {
20039        self.insert_uuid(UuidVersion::V4, window, cx);
20040    }
20041
20042    pub fn insert_uuid_v7(
20043        &mut self,
20044        _: &InsertUuidV7,
20045        window: &mut Window,
20046        cx: &mut Context<Self>,
20047    ) {
20048        self.insert_uuid(UuidVersion::V7, window, cx);
20049    }
20050
20051    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20053        self.transact(window, cx, |this, window, cx| {
20054            let edits = this
20055                .selections
20056                .all::<Point>(cx)
20057                .into_iter()
20058                .map(|selection| {
20059                    let uuid = match version {
20060                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20061                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20062                    };
20063
20064                    (selection.range(), uuid.to_string())
20065                });
20066            this.edit(edits, cx);
20067            this.refresh_edit_prediction(true, false, window, cx);
20068        });
20069    }
20070
20071    pub fn open_selections_in_multibuffer(
20072        &mut self,
20073        _: &OpenSelectionsInMultibuffer,
20074        window: &mut Window,
20075        cx: &mut Context<Self>,
20076    ) {
20077        let multibuffer = self.buffer.read(cx);
20078
20079        let Some(buffer) = multibuffer.as_singleton() else {
20080            return;
20081        };
20082
20083        let Some(workspace) = self.workspace() else {
20084            return;
20085        };
20086
20087        let title = multibuffer.title(cx).to_string();
20088
20089        let locations = self
20090            .selections
20091            .all_anchors(cx)
20092            .iter()
20093            .map(|selection| {
20094                (
20095                    buffer.clone(),
20096                    (selection.start.text_anchor..selection.end.text_anchor)
20097                        .to_point(buffer.read(cx)),
20098                )
20099            })
20100            .into_group_map();
20101
20102        cx.spawn_in(window, async move |_, cx| {
20103            workspace.update_in(cx, |workspace, window, cx| {
20104                Self::open_locations_in_multibuffer(
20105                    workspace,
20106                    locations,
20107                    format!("Selections for '{title}'"),
20108                    false,
20109                    MultibufferSelectionMode::All,
20110                    window,
20111                    cx,
20112                );
20113            })
20114        })
20115        .detach();
20116    }
20117
20118    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20119    /// last highlight added will be used.
20120    ///
20121    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20122    pub fn highlight_rows<T: 'static>(
20123        &mut self,
20124        range: Range<Anchor>,
20125        color: Hsla,
20126        options: RowHighlightOptions,
20127        cx: &mut Context<Self>,
20128    ) {
20129        let snapshot = self.buffer().read(cx).snapshot(cx);
20130        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20131        let ix = row_highlights.binary_search_by(|highlight| {
20132            Ordering::Equal
20133                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20134                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20135        });
20136
20137        if let Err(mut ix) = ix {
20138            let index = post_inc(&mut self.highlight_order);
20139
20140            // If this range intersects with the preceding highlight, then merge it with
20141            // the preceding highlight. Otherwise insert a new highlight.
20142            let mut merged = false;
20143            if ix > 0 {
20144                let prev_highlight = &mut row_highlights[ix - 1];
20145                if prev_highlight
20146                    .range
20147                    .end
20148                    .cmp(&range.start, &snapshot)
20149                    .is_ge()
20150                {
20151                    ix -= 1;
20152                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20153                        prev_highlight.range.end = range.end;
20154                    }
20155                    merged = true;
20156                    prev_highlight.index = index;
20157                    prev_highlight.color = color;
20158                    prev_highlight.options = options;
20159                }
20160            }
20161
20162            if !merged {
20163                row_highlights.insert(
20164                    ix,
20165                    RowHighlight {
20166                        range,
20167                        index,
20168                        color,
20169                        options,
20170                        type_id: TypeId::of::<T>(),
20171                    },
20172                );
20173            }
20174
20175            // If any of the following highlights intersect with this one, merge them.
20176            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20177                let highlight = &row_highlights[ix];
20178                if next_highlight
20179                    .range
20180                    .start
20181                    .cmp(&highlight.range.end, &snapshot)
20182                    .is_le()
20183                {
20184                    if next_highlight
20185                        .range
20186                        .end
20187                        .cmp(&highlight.range.end, &snapshot)
20188                        .is_gt()
20189                    {
20190                        row_highlights[ix].range.end = next_highlight.range.end;
20191                    }
20192                    row_highlights.remove(ix + 1);
20193                } else {
20194                    break;
20195                }
20196            }
20197        }
20198    }
20199
20200    /// Remove any highlighted row ranges of the given type that intersect the
20201    /// given ranges.
20202    pub fn remove_highlighted_rows<T: 'static>(
20203        &mut self,
20204        ranges_to_remove: Vec<Range<Anchor>>,
20205        cx: &mut Context<Self>,
20206    ) {
20207        let snapshot = self.buffer().read(cx).snapshot(cx);
20208        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20209        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20210        row_highlights.retain(|highlight| {
20211            while let Some(range_to_remove) = ranges_to_remove.peek() {
20212                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20213                    Ordering::Less | Ordering::Equal => {
20214                        ranges_to_remove.next();
20215                    }
20216                    Ordering::Greater => {
20217                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20218                            Ordering::Less | Ordering::Equal => {
20219                                return false;
20220                            }
20221                            Ordering::Greater => break,
20222                        }
20223                    }
20224                }
20225            }
20226
20227            true
20228        })
20229    }
20230
20231    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20232    pub fn clear_row_highlights<T: 'static>(&mut self) {
20233        self.highlighted_rows.remove(&TypeId::of::<T>());
20234    }
20235
20236    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20237    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20238        self.highlighted_rows
20239            .get(&TypeId::of::<T>())
20240            .map_or(&[] as &[_], |vec| vec.as_slice())
20241            .iter()
20242            .map(|highlight| (highlight.range.clone(), highlight.color))
20243    }
20244
20245    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20246    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20247    /// Allows to ignore certain kinds of highlights.
20248    pub fn highlighted_display_rows(
20249        &self,
20250        window: &mut Window,
20251        cx: &mut App,
20252    ) -> BTreeMap<DisplayRow, LineHighlight> {
20253        let snapshot = self.snapshot(window, cx);
20254        let mut used_highlight_orders = HashMap::default();
20255        self.highlighted_rows
20256            .iter()
20257            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20258            .fold(
20259                BTreeMap::<DisplayRow, LineHighlight>::new(),
20260                |mut unique_rows, highlight| {
20261                    let start = highlight.range.start.to_display_point(&snapshot);
20262                    let end = highlight.range.end.to_display_point(&snapshot);
20263                    let start_row = start.row().0;
20264                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20265                        && end.column() == 0
20266                    {
20267                        end.row().0.saturating_sub(1)
20268                    } else {
20269                        end.row().0
20270                    };
20271                    for row in start_row..=end_row {
20272                        let used_index =
20273                            used_highlight_orders.entry(row).or_insert(highlight.index);
20274                        if highlight.index >= *used_index {
20275                            *used_index = highlight.index;
20276                            unique_rows.insert(
20277                                DisplayRow(row),
20278                                LineHighlight {
20279                                    include_gutter: highlight.options.include_gutter,
20280                                    border: None,
20281                                    background: highlight.color.into(),
20282                                    type_id: Some(highlight.type_id),
20283                                },
20284                            );
20285                        }
20286                    }
20287                    unique_rows
20288                },
20289            )
20290    }
20291
20292    pub fn highlighted_display_row_for_autoscroll(
20293        &self,
20294        snapshot: &DisplaySnapshot,
20295    ) -> Option<DisplayRow> {
20296        self.highlighted_rows
20297            .values()
20298            .flat_map(|highlighted_rows| highlighted_rows.iter())
20299            .filter_map(|highlight| {
20300                if highlight.options.autoscroll {
20301                    Some(highlight.range.start.to_display_point(snapshot).row())
20302                } else {
20303                    None
20304                }
20305            })
20306            .min()
20307    }
20308
20309    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20310        self.highlight_background::<SearchWithinRange>(
20311            ranges,
20312            |colors| colors.colors().editor_document_highlight_read_background,
20313            cx,
20314        )
20315    }
20316
20317    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20318        self.breadcrumb_header = Some(new_header);
20319    }
20320
20321    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20322        self.clear_background_highlights::<SearchWithinRange>(cx);
20323    }
20324
20325    pub fn highlight_background<T: 'static>(
20326        &mut self,
20327        ranges: &[Range<Anchor>],
20328        color_fetcher: fn(&Theme) -> Hsla,
20329        cx: &mut Context<Self>,
20330    ) {
20331        self.background_highlights.insert(
20332            HighlightKey::Type(TypeId::of::<T>()),
20333            (color_fetcher, Arc::from(ranges)),
20334        );
20335        self.scrollbar_marker_state.dirty = true;
20336        cx.notify();
20337    }
20338
20339    pub fn highlight_background_key<T: 'static>(
20340        &mut self,
20341        key: usize,
20342        ranges: &[Range<Anchor>],
20343        color_fetcher: fn(&Theme) -> Hsla,
20344        cx: &mut Context<Self>,
20345    ) {
20346        self.background_highlights.insert(
20347            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20348            (color_fetcher, Arc::from(ranges)),
20349        );
20350        self.scrollbar_marker_state.dirty = true;
20351        cx.notify();
20352    }
20353
20354    pub fn clear_background_highlights<T: 'static>(
20355        &mut self,
20356        cx: &mut Context<Self>,
20357    ) -> Option<BackgroundHighlight> {
20358        let text_highlights = self
20359            .background_highlights
20360            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20361        if !text_highlights.1.is_empty() {
20362            self.scrollbar_marker_state.dirty = true;
20363            cx.notify();
20364        }
20365        Some(text_highlights)
20366    }
20367
20368    pub fn highlight_gutter<T: 'static>(
20369        &mut self,
20370        ranges: impl Into<Vec<Range<Anchor>>>,
20371        color_fetcher: fn(&App) -> Hsla,
20372        cx: &mut Context<Self>,
20373    ) {
20374        self.gutter_highlights
20375            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20376        cx.notify();
20377    }
20378
20379    pub fn clear_gutter_highlights<T: 'static>(
20380        &mut self,
20381        cx: &mut Context<Self>,
20382    ) -> Option<GutterHighlight> {
20383        cx.notify();
20384        self.gutter_highlights.remove(&TypeId::of::<T>())
20385    }
20386
20387    pub fn insert_gutter_highlight<T: 'static>(
20388        &mut self,
20389        range: Range<Anchor>,
20390        color_fetcher: fn(&App) -> Hsla,
20391        cx: &mut Context<Self>,
20392    ) {
20393        let snapshot = self.buffer().read(cx).snapshot(cx);
20394        let mut highlights = self
20395            .gutter_highlights
20396            .remove(&TypeId::of::<T>())
20397            .map(|(_, highlights)| highlights)
20398            .unwrap_or_default();
20399        let ix = highlights.binary_search_by(|highlight| {
20400            Ordering::Equal
20401                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20402                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20403        });
20404        if let Err(ix) = ix {
20405            highlights.insert(ix, range);
20406        }
20407        self.gutter_highlights
20408            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20409    }
20410
20411    pub fn remove_gutter_highlights<T: 'static>(
20412        &mut self,
20413        ranges_to_remove: Vec<Range<Anchor>>,
20414        cx: &mut Context<Self>,
20415    ) {
20416        let snapshot = self.buffer().read(cx).snapshot(cx);
20417        let Some((color_fetcher, mut gutter_highlights)) =
20418            self.gutter_highlights.remove(&TypeId::of::<T>())
20419        else {
20420            return;
20421        };
20422        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20423        gutter_highlights.retain(|highlight| {
20424            while let Some(range_to_remove) = ranges_to_remove.peek() {
20425                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20426                    Ordering::Less | Ordering::Equal => {
20427                        ranges_to_remove.next();
20428                    }
20429                    Ordering::Greater => {
20430                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20431                            Ordering::Less | Ordering::Equal => {
20432                                return false;
20433                            }
20434                            Ordering::Greater => break,
20435                        }
20436                    }
20437                }
20438            }
20439
20440            true
20441        });
20442        self.gutter_highlights
20443            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20444    }
20445
20446    #[cfg(feature = "test-support")]
20447    pub fn all_text_highlights(
20448        &self,
20449        window: &mut Window,
20450        cx: &mut Context<Self>,
20451    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20452        let snapshot = self.snapshot(window, cx);
20453        self.display_map.update(cx, |display_map, _| {
20454            display_map
20455                .all_text_highlights()
20456                .map(|highlight| {
20457                    let (style, ranges) = highlight.as_ref();
20458                    (
20459                        *style,
20460                        ranges
20461                            .iter()
20462                            .map(|range| range.clone().to_display_points(&snapshot))
20463                            .collect(),
20464                    )
20465                })
20466                .collect()
20467        })
20468    }
20469
20470    #[cfg(feature = "test-support")]
20471    pub fn all_text_background_highlights(
20472        &self,
20473        window: &mut Window,
20474        cx: &mut Context<Self>,
20475    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20476        let snapshot = self.snapshot(window, cx);
20477        let buffer = &snapshot.buffer_snapshot();
20478        let start = buffer.anchor_before(0);
20479        let end = buffer.anchor_after(buffer.len());
20480        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20481    }
20482
20483    #[cfg(any(test, feature = "test-support"))]
20484    pub fn sorted_background_highlights_in_range(
20485        &self,
20486        search_range: Range<Anchor>,
20487        display_snapshot: &DisplaySnapshot,
20488        theme: &Theme,
20489    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20490        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20491        res.sort_by(|a, b| {
20492            a.0.start
20493                .cmp(&b.0.start)
20494                .then_with(|| a.0.end.cmp(&b.0.end))
20495                .then_with(|| a.1.cmp(&b.1))
20496        });
20497        res
20498    }
20499
20500    #[cfg(feature = "test-support")]
20501    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20502        let snapshot = self.buffer().read(cx).snapshot(cx);
20503
20504        let highlights = self
20505            .background_highlights
20506            .get(&HighlightKey::Type(TypeId::of::<
20507                items::BufferSearchHighlights,
20508            >()));
20509
20510        if let Some((_color, ranges)) = highlights {
20511            ranges
20512                .iter()
20513                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20514                .collect_vec()
20515        } else {
20516            vec![]
20517        }
20518    }
20519
20520    fn document_highlights_for_position<'a>(
20521        &'a self,
20522        position: Anchor,
20523        buffer: &'a MultiBufferSnapshot,
20524    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20525        let read_highlights = self
20526            .background_highlights
20527            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20528            .map(|h| &h.1);
20529        let write_highlights = self
20530            .background_highlights
20531            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20532            .map(|h| &h.1);
20533        let left_position = position.bias_left(buffer);
20534        let right_position = position.bias_right(buffer);
20535        read_highlights
20536            .into_iter()
20537            .chain(write_highlights)
20538            .flat_map(move |ranges| {
20539                let start_ix = match ranges.binary_search_by(|probe| {
20540                    let cmp = probe.end.cmp(&left_position, buffer);
20541                    if cmp.is_ge() {
20542                        Ordering::Greater
20543                    } else {
20544                        Ordering::Less
20545                    }
20546                }) {
20547                    Ok(i) | Err(i) => i,
20548                };
20549
20550                ranges[start_ix..]
20551                    .iter()
20552                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20553            })
20554    }
20555
20556    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20557        self.background_highlights
20558            .get(&HighlightKey::Type(TypeId::of::<T>()))
20559            .is_some_and(|(_, highlights)| !highlights.is_empty())
20560    }
20561
20562    /// Returns all background highlights for a given range.
20563    ///
20564    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20565    pub fn background_highlights_in_range(
20566        &self,
20567        search_range: Range<Anchor>,
20568        display_snapshot: &DisplaySnapshot,
20569        theme: &Theme,
20570    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20571        let mut results = Vec::new();
20572        for (color_fetcher, ranges) in self.background_highlights.values() {
20573            let color = color_fetcher(theme);
20574            let start_ix = match ranges.binary_search_by(|probe| {
20575                let cmp = probe
20576                    .end
20577                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20578                if cmp.is_gt() {
20579                    Ordering::Greater
20580                } else {
20581                    Ordering::Less
20582                }
20583            }) {
20584                Ok(i) | Err(i) => i,
20585            };
20586            for range in &ranges[start_ix..] {
20587                if range
20588                    .start
20589                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20590                    .is_ge()
20591                {
20592                    break;
20593                }
20594
20595                let start = range.start.to_display_point(display_snapshot);
20596                let end = range.end.to_display_point(display_snapshot);
20597                results.push((start..end, color))
20598            }
20599        }
20600        results
20601    }
20602
20603    pub fn gutter_highlights_in_range(
20604        &self,
20605        search_range: Range<Anchor>,
20606        display_snapshot: &DisplaySnapshot,
20607        cx: &App,
20608    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20609        let mut results = Vec::new();
20610        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20611            let color = color_fetcher(cx);
20612            let start_ix = match ranges.binary_search_by(|probe| {
20613                let cmp = probe
20614                    .end
20615                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20616                if cmp.is_gt() {
20617                    Ordering::Greater
20618                } else {
20619                    Ordering::Less
20620                }
20621            }) {
20622                Ok(i) | Err(i) => i,
20623            };
20624            for range in &ranges[start_ix..] {
20625                if range
20626                    .start
20627                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20628                    .is_ge()
20629                {
20630                    break;
20631                }
20632
20633                let start = range.start.to_display_point(display_snapshot);
20634                let end = range.end.to_display_point(display_snapshot);
20635                results.push((start..end, color))
20636            }
20637        }
20638        results
20639    }
20640
20641    /// Get the text ranges corresponding to the redaction query
20642    pub fn redacted_ranges(
20643        &self,
20644        search_range: Range<Anchor>,
20645        display_snapshot: &DisplaySnapshot,
20646        cx: &App,
20647    ) -> Vec<Range<DisplayPoint>> {
20648        display_snapshot
20649            .buffer_snapshot()
20650            .redacted_ranges(search_range, |file| {
20651                if let Some(file) = file {
20652                    file.is_private()
20653                        && EditorSettings::get(
20654                            Some(SettingsLocation {
20655                                worktree_id: file.worktree_id(cx),
20656                                path: file.path().as_ref(),
20657                            }),
20658                            cx,
20659                        )
20660                        .redact_private_values
20661                } else {
20662                    false
20663                }
20664            })
20665            .map(|range| {
20666                range.start.to_display_point(display_snapshot)
20667                    ..range.end.to_display_point(display_snapshot)
20668            })
20669            .collect()
20670    }
20671
20672    pub fn highlight_text_key<T: 'static>(
20673        &mut self,
20674        key: usize,
20675        ranges: Vec<Range<Anchor>>,
20676        style: HighlightStyle,
20677        cx: &mut Context<Self>,
20678    ) {
20679        self.display_map.update(cx, |map, _| {
20680            map.highlight_text(
20681                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20682                ranges,
20683                style,
20684            );
20685        });
20686        cx.notify();
20687    }
20688
20689    pub fn highlight_text<T: 'static>(
20690        &mut self,
20691        ranges: Vec<Range<Anchor>>,
20692        style: HighlightStyle,
20693        cx: &mut Context<Self>,
20694    ) {
20695        self.display_map.update(cx, |map, _| {
20696            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20697        });
20698        cx.notify();
20699    }
20700
20701    pub(crate) fn highlight_inlays<T: 'static>(
20702        &mut self,
20703        highlights: Vec<InlayHighlight>,
20704        style: HighlightStyle,
20705        cx: &mut Context<Self>,
20706    ) {
20707        self.display_map.update(cx, |map, _| {
20708            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20709        });
20710        cx.notify();
20711    }
20712
20713    pub fn text_highlights<'a, T: 'static>(
20714        &'a self,
20715        cx: &'a App,
20716    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20717        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20718    }
20719
20720    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20721        let cleared = self
20722            .display_map
20723            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20724        if cleared {
20725            cx.notify();
20726        }
20727    }
20728
20729    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20730        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20731            && self.focus_handle.is_focused(window)
20732    }
20733
20734    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20735        self.show_cursor_when_unfocused = is_enabled;
20736        cx.notify();
20737    }
20738
20739    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20740        cx.notify();
20741    }
20742
20743    fn on_debug_session_event(
20744        &mut self,
20745        _session: Entity<Session>,
20746        event: &SessionEvent,
20747        cx: &mut Context<Self>,
20748    ) {
20749        if let SessionEvent::InvalidateInlineValue = event {
20750            self.refresh_inline_values(cx);
20751        }
20752    }
20753
20754    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20755        let Some(project) = self.project.clone() else {
20756            return;
20757        };
20758
20759        if !self.inline_value_cache.enabled {
20760            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20761            self.splice_inlays(&inlays, Vec::new(), cx);
20762            return;
20763        }
20764
20765        let current_execution_position = self
20766            .highlighted_rows
20767            .get(&TypeId::of::<ActiveDebugLine>())
20768            .and_then(|lines| lines.last().map(|line| line.range.end));
20769
20770        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20771            let inline_values = editor
20772                .update(cx, |editor, cx| {
20773                    let Some(current_execution_position) = current_execution_position else {
20774                        return Some(Task::ready(Ok(Vec::new())));
20775                    };
20776
20777                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20778                        let snapshot = buffer.snapshot(cx);
20779
20780                        let excerpt = snapshot.excerpt_containing(
20781                            current_execution_position..current_execution_position,
20782                        )?;
20783
20784                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20785                    })?;
20786
20787                    let range =
20788                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20789
20790                    project.inline_values(buffer, range, cx)
20791                })
20792                .ok()
20793                .flatten()?
20794                .await
20795                .context("refreshing debugger inlays")
20796                .log_err()?;
20797
20798            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20799
20800            for (buffer_id, inline_value) in inline_values
20801                .into_iter()
20802                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20803            {
20804                buffer_inline_values
20805                    .entry(buffer_id)
20806                    .or_default()
20807                    .push(inline_value);
20808            }
20809
20810            editor
20811                .update(cx, |editor, cx| {
20812                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20813                    let mut new_inlays = Vec::default();
20814
20815                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20816                        let buffer_id = buffer_snapshot.remote_id();
20817                        buffer_inline_values
20818                            .get(&buffer_id)
20819                            .into_iter()
20820                            .flatten()
20821                            .for_each(|hint| {
20822                                let inlay = Inlay::debugger(
20823                                    post_inc(&mut editor.next_inlay_id),
20824                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20825                                    hint.text(),
20826                                );
20827                                if !inlay.text().chars().contains(&'\n') {
20828                                    new_inlays.push(inlay);
20829                                }
20830                            });
20831                    }
20832
20833                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20834                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20835
20836                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20837                })
20838                .ok()?;
20839            Some(())
20840        });
20841    }
20842
20843    fn on_buffer_event(
20844        &mut self,
20845        multibuffer: &Entity<MultiBuffer>,
20846        event: &multi_buffer::Event,
20847        window: &mut Window,
20848        cx: &mut Context<Self>,
20849    ) {
20850        match event {
20851            multi_buffer::Event::Edited {
20852                singleton_buffer_edited,
20853                edited_buffer,
20854            } => {
20855                self.scrollbar_marker_state.dirty = true;
20856                self.active_indent_guides_state.dirty = true;
20857                self.refresh_active_diagnostics(cx);
20858                self.refresh_code_actions(window, cx);
20859                self.refresh_selected_text_highlights(true, window, cx);
20860                self.refresh_single_line_folds(window, cx);
20861                refresh_matching_bracket_highlights(self, cx);
20862                if self.has_active_edit_prediction() {
20863                    self.update_visible_edit_prediction(window, cx);
20864                }
20865                if let Some(project) = self.project.as_ref()
20866                    && let Some(edited_buffer) = edited_buffer
20867                {
20868                    project.update(cx, |project, cx| {
20869                        self.registered_buffers
20870                            .entry(edited_buffer.read(cx).remote_id())
20871                            .or_insert_with(|| {
20872                                project.register_buffer_with_language_servers(edited_buffer, cx)
20873                            });
20874                    });
20875                }
20876                cx.emit(EditorEvent::BufferEdited);
20877                cx.emit(SearchEvent::MatchesInvalidated);
20878
20879                if let Some(buffer) = edited_buffer {
20880                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20881                }
20882
20883                if *singleton_buffer_edited {
20884                    if let Some(buffer) = edited_buffer
20885                        && buffer.read(cx).file().is_none()
20886                    {
20887                        cx.emit(EditorEvent::TitleChanged);
20888                    }
20889                    if let Some(project) = &self.project {
20890                        #[allow(clippy::mutable_key_type)]
20891                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20892                            multibuffer
20893                                .all_buffers()
20894                                .into_iter()
20895                                .filter_map(|buffer| {
20896                                    buffer.update(cx, |buffer, cx| {
20897                                        let language = buffer.language()?;
20898                                        let should_discard = project.update(cx, |project, cx| {
20899                                            project.is_local()
20900                                                && !project.has_language_servers_for(buffer, cx)
20901                                        });
20902                                        should_discard.not().then_some(language.clone())
20903                                    })
20904                                })
20905                                .collect::<HashSet<_>>()
20906                        });
20907                        if !languages_affected.is_empty() {
20908                            self.refresh_inlay_hints(
20909                                InlayHintRefreshReason::BufferEdited(languages_affected),
20910                                cx,
20911                            );
20912                        }
20913                    }
20914                }
20915
20916                let Some(project) = &self.project else { return };
20917                let (telemetry, is_via_ssh) = {
20918                    let project = project.read(cx);
20919                    let telemetry = project.client().telemetry().clone();
20920                    let is_via_ssh = project.is_via_remote_server();
20921                    (telemetry, is_via_ssh)
20922                };
20923                refresh_linked_ranges(self, window, cx);
20924                telemetry.log_edit_event("editor", is_via_ssh);
20925            }
20926            multi_buffer::Event::ExcerptsAdded {
20927                buffer,
20928                predecessor,
20929                excerpts,
20930            } => {
20931                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20932                let buffer_id = buffer.read(cx).remote_id();
20933                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20934                    && let Some(project) = &self.project
20935                {
20936                    update_uncommitted_diff_for_buffer(
20937                        cx.entity(),
20938                        project,
20939                        [buffer.clone()],
20940                        self.buffer.clone(),
20941                        cx,
20942                    )
20943                    .detach();
20944                }
20945                if self.active_diagnostics != ActiveDiagnostic::All {
20946                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20947                }
20948                cx.emit(EditorEvent::ExcerptsAdded {
20949                    buffer: buffer.clone(),
20950                    predecessor: *predecessor,
20951                    excerpts: excerpts.clone(),
20952                });
20953                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20954            }
20955            multi_buffer::Event::ExcerptsRemoved {
20956                ids,
20957                removed_buffer_ids,
20958            } => {
20959                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20960                let buffer = self.buffer.read(cx);
20961                self.registered_buffers
20962                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20963                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20964                cx.emit(EditorEvent::ExcerptsRemoved {
20965                    ids: ids.clone(),
20966                    removed_buffer_ids: removed_buffer_ids.clone(),
20967                });
20968            }
20969            multi_buffer::Event::ExcerptsEdited {
20970                excerpt_ids,
20971                buffer_ids,
20972            } => {
20973                self.display_map.update(cx, |map, cx| {
20974                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20975                });
20976                cx.emit(EditorEvent::ExcerptsEdited {
20977                    ids: excerpt_ids.clone(),
20978                });
20979            }
20980            multi_buffer::Event::ExcerptsExpanded { ids } => {
20981                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20982                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20983            }
20984            multi_buffer::Event::Reparsed(buffer_id) => {
20985                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20986                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20987
20988                cx.emit(EditorEvent::Reparsed(*buffer_id));
20989            }
20990            multi_buffer::Event::DiffHunksToggled => {
20991                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20992            }
20993            multi_buffer::Event::LanguageChanged(buffer_id) => {
20994                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20995                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20996                cx.emit(EditorEvent::Reparsed(*buffer_id));
20997                cx.notify();
20998            }
20999            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21000            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21001            multi_buffer::Event::FileHandleChanged
21002            | multi_buffer::Event::Reloaded
21003            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21004            multi_buffer::Event::DiagnosticsUpdated => {
21005                self.update_diagnostics_state(window, cx);
21006            }
21007            _ => {}
21008        };
21009    }
21010
21011    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21012        if !self.diagnostics_enabled() {
21013            return;
21014        }
21015        self.refresh_active_diagnostics(cx);
21016        self.refresh_inline_diagnostics(true, window, cx);
21017        self.scrollbar_marker_state.dirty = true;
21018        cx.notify();
21019    }
21020
21021    pub fn start_temporary_diff_override(&mut self) {
21022        self.load_diff_task.take();
21023        self.temporary_diff_override = true;
21024    }
21025
21026    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21027        self.temporary_diff_override = false;
21028        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21029        self.buffer.update(cx, |buffer, cx| {
21030            buffer.set_all_diff_hunks_collapsed(cx);
21031        });
21032
21033        if let Some(project) = self.project.clone() {
21034            self.load_diff_task = Some(
21035                update_uncommitted_diff_for_buffer(
21036                    cx.entity(),
21037                    &project,
21038                    self.buffer.read(cx).all_buffers(),
21039                    self.buffer.clone(),
21040                    cx,
21041                )
21042                .shared(),
21043            );
21044        }
21045    }
21046
21047    fn on_display_map_changed(
21048        &mut self,
21049        _: Entity<DisplayMap>,
21050        _: &mut Window,
21051        cx: &mut Context<Self>,
21052    ) {
21053        cx.notify();
21054    }
21055
21056    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21057        if self.diagnostics_enabled() {
21058            let new_severity = EditorSettings::get_global(cx)
21059                .diagnostics_max_severity
21060                .unwrap_or(DiagnosticSeverity::Hint);
21061            self.set_max_diagnostics_severity(new_severity, cx);
21062        }
21063        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21064        self.update_edit_prediction_settings(cx);
21065        self.refresh_edit_prediction(true, false, window, cx);
21066        self.refresh_inline_values(cx);
21067        self.refresh_inlay_hints(
21068            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21069                self.selections.newest_anchor().head(),
21070                &self.buffer.read(cx).snapshot(cx),
21071                cx,
21072            )),
21073            cx,
21074        );
21075
21076        let old_cursor_shape = self.cursor_shape;
21077        let old_show_breadcrumbs = self.show_breadcrumbs;
21078
21079        {
21080            let editor_settings = EditorSettings::get_global(cx);
21081            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21082            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21083            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21084            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21085        }
21086
21087        if old_cursor_shape != self.cursor_shape {
21088            cx.emit(EditorEvent::CursorShapeChanged);
21089        }
21090
21091        if old_show_breadcrumbs != self.show_breadcrumbs {
21092            cx.emit(EditorEvent::BreadcrumbsChanged);
21093        }
21094
21095        let project_settings = ProjectSettings::get_global(cx);
21096        self.serialize_dirty_buffers =
21097            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21098
21099        if self.mode.is_full() {
21100            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21101            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21102            if self.show_inline_diagnostics != show_inline_diagnostics {
21103                self.show_inline_diagnostics = show_inline_diagnostics;
21104                self.refresh_inline_diagnostics(false, window, cx);
21105            }
21106
21107            if self.git_blame_inline_enabled != inline_blame_enabled {
21108                self.toggle_git_blame_inline_internal(false, window, cx);
21109            }
21110
21111            let minimap_settings = EditorSettings::get_global(cx).minimap;
21112            if self.minimap_visibility != MinimapVisibility::Disabled {
21113                if self.minimap_visibility.settings_visibility()
21114                    != minimap_settings.minimap_enabled()
21115                {
21116                    self.set_minimap_visibility(
21117                        MinimapVisibility::for_mode(self.mode(), cx),
21118                        window,
21119                        cx,
21120                    );
21121                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21122                    minimap_entity.update(cx, |minimap_editor, cx| {
21123                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21124                    })
21125                }
21126            }
21127        }
21128
21129        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21130            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21131        }) {
21132            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21133                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21134            }
21135            self.refresh_colors(false, None, window, cx);
21136        }
21137
21138        cx.notify();
21139    }
21140
21141    pub fn set_searchable(&mut self, searchable: bool) {
21142        self.searchable = searchable;
21143    }
21144
21145    pub fn searchable(&self) -> bool {
21146        self.searchable
21147    }
21148
21149    fn open_proposed_changes_editor(
21150        &mut self,
21151        _: &OpenProposedChangesEditor,
21152        window: &mut Window,
21153        cx: &mut Context<Self>,
21154    ) {
21155        let Some(workspace) = self.workspace() else {
21156            cx.propagate();
21157            return;
21158        };
21159
21160        let selections = self.selections.all::<usize>(cx);
21161        let multi_buffer = self.buffer.read(cx);
21162        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21163        let mut new_selections_by_buffer = HashMap::default();
21164        for selection in selections {
21165            for (buffer, range, _) in
21166                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21167            {
21168                let mut range = range.to_point(buffer);
21169                range.start.column = 0;
21170                range.end.column = buffer.line_len(range.end.row);
21171                new_selections_by_buffer
21172                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21173                    .or_insert(Vec::new())
21174                    .push(range)
21175            }
21176        }
21177
21178        let proposed_changes_buffers = new_selections_by_buffer
21179            .into_iter()
21180            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21181            .collect::<Vec<_>>();
21182        let proposed_changes_editor = cx.new(|cx| {
21183            ProposedChangesEditor::new(
21184                "Proposed changes",
21185                proposed_changes_buffers,
21186                self.project.clone(),
21187                window,
21188                cx,
21189            )
21190        });
21191
21192        window.defer(cx, move |window, cx| {
21193            workspace.update(cx, |workspace, cx| {
21194                workspace.active_pane().update(cx, |pane, cx| {
21195                    pane.add_item(
21196                        Box::new(proposed_changes_editor),
21197                        true,
21198                        true,
21199                        None,
21200                        window,
21201                        cx,
21202                    );
21203                });
21204            });
21205        });
21206    }
21207
21208    pub fn open_excerpts_in_split(
21209        &mut self,
21210        _: &OpenExcerptsSplit,
21211        window: &mut Window,
21212        cx: &mut Context<Self>,
21213    ) {
21214        self.open_excerpts_common(None, true, window, cx)
21215    }
21216
21217    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21218        self.open_excerpts_common(None, false, window, cx)
21219    }
21220
21221    fn open_excerpts_common(
21222        &mut self,
21223        jump_data: Option<JumpData>,
21224        split: bool,
21225        window: &mut Window,
21226        cx: &mut Context<Self>,
21227    ) {
21228        let Some(workspace) = self.workspace() else {
21229            cx.propagate();
21230            return;
21231        };
21232
21233        if self.buffer.read(cx).is_singleton() {
21234            cx.propagate();
21235            return;
21236        }
21237
21238        let mut new_selections_by_buffer = HashMap::default();
21239        match &jump_data {
21240            Some(JumpData::MultiBufferPoint {
21241                excerpt_id,
21242                position,
21243                anchor,
21244                line_offset_from_top,
21245            }) => {
21246                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21247                if let Some(buffer) = multi_buffer_snapshot
21248                    .buffer_id_for_excerpt(*excerpt_id)
21249                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21250                {
21251                    let buffer_snapshot = buffer.read(cx).snapshot();
21252                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21253                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21254                    } else {
21255                        buffer_snapshot.clip_point(*position, Bias::Left)
21256                    };
21257                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21258                    new_selections_by_buffer.insert(
21259                        buffer,
21260                        (
21261                            vec![jump_to_offset..jump_to_offset],
21262                            Some(*line_offset_from_top),
21263                        ),
21264                    );
21265                }
21266            }
21267            Some(JumpData::MultiBufferRow {
21268                row,
21269                line_offset_from_top,
21270            }) => {
21271                let point = MultiBufferPoint::new(row.0, 0);
21272                if let Some((buffer, buffer_point, _)) =
21273                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21274                {
21275                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21276                    new_selections_by_buffer
21277                        .entry(buffer)
21278                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21279                        .0
21280                        .push(buffer_offset..buffer_offset)
21281                }
21282            }
21283            None => {
21284                let selections = self.selections.all::<usize>(cx);
21285                let multi_buffer = self.buffer.read(cx);
21286                for selection in selections {
21287                    for (snapshot, range, _, anchor) in multi_buffer
21288                        .snapshot(cx)
21289                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21290                    {
21291                        if let Some(anchor) = anchor {
21292                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21293                            else {
21294                                continue;
21295                            };
21296                            let offset = text::ToOffset::to_offset(
21297                                &anchor.text_anchor,
21298                                &buffer_handle.read(cx).snapshot(),
21299                            );
21300                            let range = offset..offset;
21301                            new_selections_by_buffer
21302                                .entry(buffer_handle)
21303                                .or_insert((Vec::new(), None))
21304                                .0
21305                                .push(range)
21306                        } else {
21307                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21308                            else {
21309                                continue;
21310                            };
21311                            new_selections_by_buffer
21312                                .entry(buffer_handle)
21313                                .or_insert((Vec::new(), None))
21314                                .0
21315                                .push(range)
21316                        }
21317                    }
21318                }
21319            }
21320        }
21321
21322        new_selections_by_buffer
21323            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21324
21325        if new_selections_by_buffer.is_empty() {
21326            return;
21327        }
21328
21329        // We defer the pane interaction because we ourselves are a workspace item
21330        // and activating a new item causes the pane to call a method on us reentrantly,
21331        // which panics if we're on the stack.
21332        window.defer(cx, move |window, cx| {
21333            workspace.update(cx, |workspace, cx| {
21334                let pane = if split {
21335                    workspace.adjacent_pane(window, cx)
21336                } else {
21337                    workspace.active_pane().clone()
21338                };
21339
21340                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21341                    let editor = buffer
21342                        .read(cx)
21343                        .file()
21344                        .is_none()
21345                        .then(|| {
21346                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21347                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21348                            // Instead, we try to activate the existing editor in the pane first.
21349                            let (editor, pane_item_index) =
21350                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21351                                    let editor = item.downcast::<Editor>()?;
21352                                    let singleton_buffer =
21353                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21354                                    if singleton_buffer == buffer {
21355                                        Some((editor, i))
21356                                    } else {
21357                                        None
21358                                    }
21359                                })?;
21360                            pane.update(cx, |pane, cx| {
21361                                pane.activate_item(pane_item_index, true, true, window, cx)
21362                            });
21363                            Some(editor)
21364                        })
21365                        .flatten()
21366                        .unwrap_or_else(|| {
21367                            workspace.open_project_item::<Self>(
21368                                pane.clone(),
21369                                buffer,
21370                                true,
21371                                true,
21372                                window,
21373                                cx,
21374                            )
21375                        });
21376
21377                    editor.update(cx, |editor, cx| {
21378                        let autoscroll = match scroll_offset {
21379                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21380                            None => Autoscroll::newest(),
21381                        };
21382                        let nav_history = editor.nav_history.take();
21383                        editor.change_selections(
21384                            SelectionEffects::scroll(autoscroll),
21385                            window,
21386                            cx,
21387                            |s| {
21388                                s.select_ranges(ranges);
21389                            },
21390                        );
21391                        editor.nav_history = nav_history;
21392                    });
21393                }
21394            })
21395        });
21396    }
21397
21398    // For now, don't allow opening excerpts in buffers that aren't backed by
21399    // regular project files.
21400    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21401        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21402    }
21403
21404    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21405        let snapshot = self.buffer.read(cx).read(cx);
21406        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21407        Some(
21408            ranges
21409                .iter()
21410                .map(move |range| {
21411                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21412                })
21413                .collect(),
21414        )
21415    }
21416
21417    fn selection_replacement_ranges(
21418        &self,
21419        range: Range<OffsetUtf16>,
21420        cx: &mut App,
21421    ) -> Vec<Range<OffsetUtf16>> {
21422        let selections = self.selections.all::<OffsetUtf16>(cx);
21423        let newest_selection = selections
21424            .iter()
21425            .max_by_key(|selection| selection.id)
21426            .unwrap();
21427        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21428        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21429        let snapshot = self.buffer.read(cx).read(cx);
21430        selections
21431            .into_iter()
21432            .map(|mut selection| {
21433                selection.start.0 =
21434                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21435                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21436                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21437                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21438            })
21439            .collect()
21440    }
21441
21442    fn report_editor_event(
21443        &self,
21444        reported_event: ReportEditorEvent,
21445        file_extension: Option<String>,
21446        cx: &App,
21447    ) {
21448        if cfg!(any(test, feature = "test-support")) {
21449            return;
21450        }
21451
21452        let Some(project) = &self.project else { return };
21453
21454        // If None, we are in a file without an extension
21455        let file = self
21456            .buffer
21457            .read(cx)
21458            .as_singleton()
21459            .and_then(|b| b.read(cx).file());
21460        let file_extension = file_extension.or(file
21461            .as_ref()
21462            .and_then(|file| Path::new(file.file_name(cx)).extension())
21463            .and_then(|e| e.to_str())
21464            .map(|a| a.to_string()));
21465
21466        let vim_mode = vim_enabled(cx);
21467
21468        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21469        let copilot_enabled = edit_predictions_provider
21470            == language::language_settings::EditPredictionProvider::Copilot;
21471        let copilot_enabled_for_language = self
21472            .buffer
21473            .read(cx)
21474            .language_settings(cx)
21475            .show_edit_predictions;
21476
21477        let project = project.read(cx);
21478        let event_type = reported_event.event_type();
21479
21480        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21481            telemetry::event!(
21482                event_type,
21483                type = if auto_saved {"autosave"} else {"manual"},
21484                file_extension,
21485                vim_mode,
21486                copilot_enabled,
21487                copilot_enabled_for_language,
21488                edit_predictions_provider,
21489                is_via_ssh = project.is_via_remote_server(),
21490            );
21491        } else {
21492            telemetry::event!(
21493                event_type,
21494                file_extension,
21495                vim_mode,
21496                copilot_enabled,
21497                copilot_enabled_for_language,
21498                edit_predictions_provider,
21499                is_via_ssh = project.is_via_remote_server(),
21500            );
21501        };
21502    }
21503
21504    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21505    /// with each line being an array of {text, highlight} objects.
21506    fn copy_highlight_json(
21507        &mut self,
21508        _: &CopyHighlightJson,
21509        window: &mut Window,
21510        cx: &mut Context<Self>,
21511    ) {
21512        #[derive(Serialize)]
21513        struct Chunk<'a> {
21514            text: String,
21515            highlight: Option<&'a str>,
21516        }
21517
21518        let snapshot = self.buffer.read(cx).snapshot(cx);
21519        let range = self
21520            .selected_text_range(false, window, cx)
21521            .and_then(|selection| {
21522                if selection.range.is_empty() {
21523                    None
21524                } else {
21525                    Some(selection.range)
21526                }
21527            })
21528            .unwrap_or_else(|| 0..snapshot.len());
21529
21530        let chunks = snapshot.chunks(range, true);
21531        let mut lines = Vec::new();
21532        let mut line: VecDeque<Chunk> = VecDeque::new();
21533
21534        let Some(style) = self.style.as_ref() else {
21535            return;
21536        };
21537
21538        for chunk in chunks {
21539            let highlight = chunk
21540                .syntax_highlight_id
21541                .and_then(|id| id.name(&style.syntax));
21542            let mut chunk_lines = chunk.text.split('\n').peekable();
21543            while let Some(text) = chunk_lines.next() {
21544                let mut merged_with_last_token = false;
21545                if let Some(last_token) = line.back_mut()
21546                    && last_token.highlight == highlight
21547                {
21548                    last_token.text.push_str(text);
21549                    merged_with_last_token = true;
21550                }
21551
21552                if !merged_with_last_token {
21553                    line.push_back(Chunk {
21554                        text: text.into(),
21555                        highlight,
21556                    });
21557                }
21558
21559                if chunk_lines.peek().is_some() {
21560                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21561                        line.pop_front();
21562                    }
21563                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21564                        line.pop_back();
21565                    }
21566
21567                    lines.push(mem::take(&mut line));
21568                }
21569            }
21570        }
21571
21572        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21573            return;
21574        };
21575        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21576    }
21577
21578    pub fn open_context_menu(
21579        &mut self,
21580        _: &OpenContextMenu,
21581        window: &mut Window,
21582        cx: &mut Context<Self>,
21583    ) {
21584        self.request_autoscroll(Autoscroll::newest(), cx);
21585        let position = self.selections.newest_display(cx).start;
21586        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21587    }
21588
21589    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21590        &self.inlay_hint_cache
21591    }
21592
21593    pub fn replay_insert_event(
21594        &mut self,
21595        text: &str,
21596        relative_utf16_range: Option<Range<isize>>,
21597        window: &mut Window,
21598        cx: &mut Context<Self>,
21599    ) {
21600        if !self.input_enabled {
21601            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21602            return;
21603        }
21604        if let Some(relative_utf16_range) = relative_utf16_range {
21605            let selections = self.selections.all::<OffsetUtf16>(cx);
21606            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21607                let new_ranges = selections.into_iter().map(|range| {
21608                    let start = OffsetUtf16(
21609                        range
21610                            .head()
21611                            .0
21612                            .saturating_add_signed(relative_utf16_range.start),
21613                    );
21614                    let end = OffsetUtf16(
21615                        range
21616                            .head()
21617                            .0
21618                            .saturating_add_signed(relative_utf16_range.end),
21619                    );
21620                    start..end
21621                });
21622                s.select_ranges(new_ranges);
21623            });
21624        }
21625
21626        self.handle_input(text, window, cx);
21627    }
21628
21629    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21630        let Some(provider) = self.semantics_provider.as_ref() else {
21631            return false;
21632        };
21633
21634        let mut supports = false;
21635        self.buffer().update(cx, |this, cx| {
21636            this.for_each_buffer(|buffer| {
21637                supports |= provider.supports_inlay_hints(buffer, cx);
21638            });
21639        });
21640
21641        supports
21642    }
21643
21644    pub fn is_focused(&self, window: &Window) -> bool {
21645        self.focus_handle.is_focused(window)
21646    }
21647
21648    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21649        cx.emit(EditorEvent::Focused);
21650
21651        if let Some(descendant) = self
21652            .last_focused_descendant
21653            .take()
21654            .and_then(|descendant| descendant.upgrade())
21655        {
21656            window.focus(&descendant);
21657        } else {
21658            if let Some(blame) = self.blame.as_ref() {
21659                blame.update(cx, GitBlame::focus)
21660            }
21661
21662            self.blink_manager.update(cx, BlinkManager::enable);
21663            self.show_cursor_names(window, cx);
21664            self.buffer.update(cx, |buffer, cx| {
21665                buffer.finalize_last_transaction(cx);
21666                if self.leader_id.is_none() {
21667                    buffer.set_active_selections(
21668                        &self.selections.disjoint_anchors_arc(),
21669                        self.selections.line_mode(),
21670                        self.cursor_shape,
21671                        cx,
21672                    );
21673                }
21674            });
21675        }
21676    }
21677
21678    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21679        cx.emit(EditorEvent::FocusedIn)
21680    }
21681
21682    fn handle_focus_out(
21683        &mut self,
21684        event: FocusOutEvent,
21685        _window: &mut Window,
21686        cx: &mut Context<Self>,
21687    ) {
21688        if event.blurred != self.focus_handle {
21689            self.last_focused_descendant = Some(event.blurred);
21690        }
21691        self.selection_drag_state = SelectionDragState::None;
21692        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21693    }
21694
21695    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21696        self.blink_manager.update(cx, BlinkManager::disable);
21697        self.buffer
21698            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21699
21700        if let Some(blame) = self.blame.as_ref() {
21701            blame.update(cx, GitBlame::blur)
21702        }
21703        if !self.hover_state.focused(window, cx) {
21704            hide_hover(self, cx);
21705        }
21706        if !self
21707            .context_menu
21708            .borrow()
21709            .as_ref()
21710            .is_some_and(|context_menu| context_menu.focused(window, cx))
21711        {
21712            self.hide_context_menu(window, cx);
21713        }
21714        self.take_active_edit_prediction(cx);
21715        cx.emit(EditorEvent::Blurred);
21716        cx.notify();
21717    }
21718
21719    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21720        let mut pending: String = window
21721            .pending_input_keystrokes()
21722            .into_iter()
21723            .flatten()
21724            .filter_map(|keystroke| {
21725                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21726                    keystroke.key_char.clone()
21727                } else {
21728                    None
21729                }
21730            })
21731            .collect();
21732
21733        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21734            pending = "".to_string();
21735        }
21736
21737        let existing_pending = self
21738            .text_highlights::<PendingInput>(cx)
21739            .map(|(_, ranges)| ranges.to_vec());
21740        if existing_pending.is_none() && pending.is_empty() {
21741            return;
21742        }
21743        let transaction =
21744            self.transact(window, cx, |this, window, cx| {
21745                let selections = this.selections.all::<usize>(cx);
21746                let edits = selections
21747                    .iter()
21748                    .map(|selection| (selection.end..selection.end, pending.clone()));
21749                this.edit(edits, cx);
21750                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21751                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21752                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21753                    }));
21754                });
21755                if let Some(existing_ranges) = existing_pending {
21756                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21757                    this.edit(edits, cx);
21758                }
21759            });
21760
21761        let snapshot = self.snapshot(window, cx);
21762        let ranges = self
21763            .selections
21764            .all::<usize>(cx)
21765            .into_iter()
21766            .map(|selection| {
21767                snapshot.buffer_snapshot().anchor_after(selection.end)
21768                    ..snapshot
21769                        .buffer_snapshot()
21770                        .anchor_before(selection.end + pending.len())
21771            })
21772            .collect();
21773
21774        if pending.is_empty() {
21775            self.clear_highlights::<PendingInput>(cx);
21776        } else {
21777            self.highlight_text::<PendingInput>(
21778                ranges,
21779                HighlightStyle {
21780                    underline: Some(UnderlineStyle {
21781                        thickness: px(1.),
21782                        color: None,
21783                        wavy: false,
21784                    }),
21785                    ..Default::default()
21786                },
21787                cx,
21788            );
21789        }
21790
21791        self.ime_transaction = self.ime_transaction.or(transaction);
21792        if let Some(transaction) = self.ime_transaction {
21793            self.buffer.update(cx, |buffer, cx| {
21794                buffer.group_until_transaction(transaction, cx);
21795            });
21796        }
21797
21798        if self.text_highlights::<PendingInput>(cx).is_none() {
21799            self.ime_transaction.take();
21800        }
21801    }
21802
21803    pub fn register_action_renderer(
21804        &mut self,
21805        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21806    ) -> Subscription {
21807        let id = self.next_editor_action_id.post_inc();
21808        self.editor_actions
21809            .borrow_mut()
21810            .insert(id, Box::new(listener));
21811
21812        let editor_actions = self.editor_actions.clone();
21813        Subscription::new(move || {
21814            editor_actions.borrow_mut().remove(&id);
21815        })
21816    }
21817
21818    pub fn register_action<A: Action>(
21819        &mut self,
21820        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21821    ) -> Subscription {
21822        let id = self.next_editor_action_id.post_inc();
21823        let listener = Arc::new(listener);
21824        self.editor_actions.borrow_mut().insert(
21825            id,
21826            Box::new(move |_, window, _| {
21827                let listener = listener.clone();
21828                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21829                    let action = action.downcast_ref().unwrap();
21830                    if phase == DispatchPhase::Bubble {
21831                        listener(action, window, cx)
21832                    }
21833                })
21834            }),
21835        );
21836
21837        let editor_actions = self.editor_actions.clone();
21838        Subscription::new(move || {
21839            editor_actions.borrow_mut().remove(&id);
21840        })
21841    }
21842
21843    pub fn file_header_size(&self) -> u32 {
21844        FILE_HEADER_HEIGHT
21845    }
21846
21847    pub fn restore(
21848        &mut self,
21849        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21850        window: &mut Window,
21851        cx: &mut Context<Self>,
21852    ) {
21853        let workspace = self.workspace();
21854        let project = self.project();
21855        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21856            let mut tasks = Vec::new();
21857            for (buffer_id, changes) in revert_changes {
21858                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21859                    buffer.update(cx, |buffer, cx| {
21860                        buffer.edit(
21861                            changes
21862                                .into_iter()
21863                                .map(|(range, text)| (range, text.to_string())),
21864                            None,
21865                            cx,
21866                        );
21867                    });
21868
21869                    if let Some(project) =
21870                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21871                    {
21872                        project.update(cx, |project, cx| {
21873                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21874                        })
21875                    }
21876                }
21877            }
21878            tasks
21879        });
21880        cx.spawn_in(window, async move |_, cx| {
21881            for (buffer, task) in save_tasks {
21882                let result = task.await;
21883                if result.is_err() {
21884                    let Some(path) = buffer
21885                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21886                        .ok()
21887                    else {
21888                        continue;
21889                    };
21890                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21891                        let Some(task) = cx
21892                            .update_window_entity(workspace, |workspace, window, cx| {
21893                                workspace
21894                                    .open_path_preview(path, None, false, false, false, window, cx)
21895                            })
21896                            .ok()
21897                        else {
21898                            continue;
21899                        };
21900                        task.await.log_err();
21901                    }
21902                }
21903            }
21904        })
21905        .detach();
21906        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21907            selections.refresh()
21908        });
21909    }
21910
21911    pub fn to_pixel_point(
21912        &self,
21913        source: multi_buffer::Anchor,
21914        editor_snapshot: &EditorSnapshot,
21915        window: &mut Window,
21916    ) -> Option<gpui::Point<Pixels>> {
21917        let source_point = source.to_display_point(editor_snapshot);
21918        self.display_to_pixel_point(source_point, editor_snapshot, window)
21919    }
21920
21921    pub fn display_to_pixel_point(
21922        &self,
21923        source: DisplayPoint,
21924        editor_snapshot: &EditorSnapshot,
21925        window: &mut Window,
21926    ) -> Option<gpui::Point<Pixels>> {
21927        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21928        let text_layout_details = self.text_layout_details(window);
21929        let scroll_top = text_layout_details
21930            .scroll_anchor
21931            .scroll_position(editor_snapshot)
21932            .y;
21933
21934        if source.row().as_f64() < scroll_top.floor() {
21935            return None;
21936        }
21937        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21938        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21939        Some(gpui::Point::new(source_x, source_y))
21940    }
21941
21942    pub fn has_visible_completions_menu(&self) -> bool {
21943        !self.edit_prediction_preview_is_active()
21944            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21945                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21946            })
21947    }
21948
21949    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21950        if self.mode.is_minimap() {
21951            return;
21952        }
21953        self.addons
21954            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21955    }
21956
21957    pub fn unregister_addon<T: Addon>(&mut self) {
21958        self.addons.remove(&std::any::TypeId::of::<T>());
21959    }
21960
21961    pub fn addon<T: Addon>(&self) -> Option<&T> {
21962        let type_id = std::any::TypeId::of::<T>();
21963        self.addons
21964            .get(&type_id)
21965            .and_then(|item| item.to_any().downcast_ref::<T>())
21966    }
21967
21968    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21969        let type_id = std::any::TypeId::of::<T>();
21970        self.addons
21971            .get_mut(&type_id)
21972            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21973    }
21974
21975    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21976        let text_layout_details = self.text_layout_details(window);
21977        let style = &text_layout_details.editor_style;
21978        let font_id = window.text_system().resolve_font(&style.text.font());
21979        let font_size = style.text.font_size.to_pixels(window.rem_size());
21980        let line_height = style.text.line_height_in_pixels(window.rem_size());
21981        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21982        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21983
21984        CharacterDimensions {
21985            em_width,
21986            em_advance,
21987            line_height,
21988        }
21989    }
21990
21991    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21992        self.load_diff_task.clone()
21993    }
21994
21995    fn read_metadata_from_db(
21996        &mut self,
21997        item_id: u64,
21998        workspace_id: WorkspaceId,
21999        window: &mut Window,
22000        cx: &mut Context<Editor>,
22001    ) {
22002        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22003            && !self.mode.is_minimap()
22004            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22005        {
22006            let buffer_snapshot = OnceCell::new();
22007
22008            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22009                && !folds.is_empty()
22010            {
22011                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22012                self.fold_ranges(
22013                    folds
22014                        .into_iter()
22015                        .map(|(start, end)| {
22016                            snapshot.clip_offset(start, Bias::Left)
22017                                ..snapshot.clip_offset(end, Bias::Right)
22018                        })
22019                        .collect(),
22020                    false,
22021                    window,
22022                    cx,
22023                );
22024            }
22025
22026            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22027                && !selections.is_empty()
22028            {
22029                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22030                // skip adding the initial selection to selection history
22031                self.selection_history.mode = SelectionHistoryMode::Skipping;
22032                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22033                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22034                        snapshot.clip_offset(start, Bias::Left)
22035                            ..snapshot.clip_offset(end, Bias::Right)
22036                    }));
22037                });
22038                self.selection_history.mode = SelectionHistoryMode::Normal;
22039            };
22040        }
22041
22042        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22043    }
22044
22045    fn update_lsp_data(
22046        &mut self,
22047        ignore_cache: bool,
22048        for_buffer: Option<BufferId>,
22049        window: &mut Window,
22050        cx: &mut Context<'_, Self>,
22051    ) {
22052        self.pull_diagnostics(for_buffer, window, cx);
22053        self.refresh_colors(ignore_cache, for_buffer, window, cx);
22054    }
22055}
22056
22057fn edit_for_markdown_paste<'a>(
22058    buffer: &MultiBufferSnapshot,
22059    range: Range<usize>,
22060    to_insert: &'a str,
22061    url: Option<url::Url>,
22062) -> (Range<usize>, Cow<'a, str>) {
22063    if url.is_none() {
22064        return (range, Cow::Borrowed(to_insert));
22065    };
22066
22067    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22068
22069    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22070        Cow::Borrowed(to_insert)
22071    } else {
22072        Cow::Owned(format!("[{old_text}]({to_insert})"))
22073    };
22074    (range, new_text)
22075}
22076
22077fn vim_enabled(cx: &App) -> bool {
22078    vim_mode_setting::VimModeSetting::try_get(cx)
22079        .map(|vim_mode| vim_mode.0)
22080        .unwrap_or(false)
22081}
22082
22083fn process_completion_for_edit(
22084    completion: &Completion,
22085    intent: CompletionIntent,
22086    buffer: &Entity<Buffer>,
22087    cursor_position: &text::Anchor,
22088    cx: &mut Context<Editor>,
22089) -> CompletionEdit {
22090    let buffer = buffer.read(cx);
22091    let buffer_snapshot = buffer.snapshot();
22092    let (snippet, new_text) = if completion.is_snippet() {
22093        let mut snippet_source = completion.new_text.clone();
22094        // Workaround for typescript language server issues so that methods don't expand within
22095        // strings and functions with type expressions. The previous point is used because the query
22096        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22097        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22098        let previous_point = if previous_point.column > 0 {
22099            cursor_position.to_previous_offset(&buffer_snapshot)
22100        } else {
22101            cursor_position.to_offset(&buffer_snapshot)
22102        };
22103        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22104            && scope.prefers_label_for_snippet_in_completion()
22105            && let Some(label) = completion.label()
22106            && matches!(
22107                completion.kind(),
22108                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22109            )
22110        {
22111            snippet_source = label;
22112        }
22113        match Snippet::parse(&snippet_source).log_err() {
22114            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22115            None => (None, completion.new_text.clone()),
22116        }
22117    } else {
22118        (None, completion.new_text.clone())
22119    };
22120
22121    let mut range_to_replace = {
22122        let replace_range = &completion.replace_range;
22123        if let CompletionSource::Lsp {
22124            insert_range: Some(insert_range),
22125            ..
22126        } = &completion.source
22127        {
22128            debug_assert_eq!(
22129                insert_range.start, replace_range.start,
22130                "insert_range and replace_range should start at the same position"
22131            );
22132            debug_assert!(
22133                insert_range
22134                    .start
22135                    .cmp(cursor_position, &buffer_snapshot)
22136                    .is_le(),
22137                "insert_range should start before or at cursor position"
22138            );
22139            debug_assert!(
22140                replace_range
22141                    .start
22142                    .cmp(cursor_position, &buffer_snapshot)
22143                    .is_le(),
22144                "replace_range should start before or at cursor position"
22145            );
22146
22147            let should_replace = match intent {
22148                CompletionIntent::CompleteWithInsert => false,
22149                CompletionIntent::CompleteWithReplace => true,
22150                CompletionIntent::Complete | CompletionIntent::Compose => {
22151                    let insert_mode =
22152                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22153                            .completions
22154                            .lsp_insert_mode;
22155                    match insert_mode {
22156                        LspInsertMode::Insert => false,
22157                        LspInsertMode::Replace => true,
22158                        LspInsertMode::ReplaceSubsequence => {
22159                            let mut text_to_replace = buffer.chars_for_range(
22160                                buffer.anchor_before(replace_range.start)
22161                                    ..buffer.anchor_after(replace_range.end),
22162                            );
22163                            let mut current_needle = text_to_replace.next();
22164                            for haystack_ch in completion.label.text.chars() {
22165                                if let Some(needle_ch) = current_needle
22166                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22167                                {
22168                                    current_needle = text_to_replace.next();
22169                                }
22170                            }
22171                            current_needle.is_none()
22172                        }
22173                        LspInsertMode::ReplaceSuffix => {
22174                            if replace_range
22175                                .end
22176                                .cmp(cursor_position, &buffer_snapshot)
22177                                .is_gt()
22178                            {
22179                                let range_after_cursor = *cursor_position..replace_range.end;
22180                                let text_after_cursor = buffer
22181                                    .text_for_range(
22182                                        buffer.anchor_before(range_after_cursor.start)
22183                                            ..buffer.anchor_after(range_after_cursor.end),
22184                                    )
22185                                    .collect::<String>()
22186                                    .to_ascii_lowercase();
22187                                completion
22188                                    .label
22189                                    .text
22190                                    .to_ascii_lowercase()
22191                                    .ends_with(&text_after_cursor)
22192                            } else {
22193                                true
22194                            }
22195                        }
22196                    }
22197                }
22198            };
22199
22200            if should_replace {
22201                replace_range.clone()
22202            } else {
22203                insert_range.clone()
22204            }
22205        } else {
22206            replace_range.clone()
22207        }
22208    };
22209
22210    if range_to_replace
22211        .end
22212        .cmp(cursor_position, &buffer_snapshot)
22213        .is_lt()
22214    {
22215        range_to_replace.end = *cursor_position;
22216    }
22217
22218    CompletionEdit {
22219        new_text,
22220        replace_range: range_to_replace.to_offset(buffer),
22221        snippet,
22222    }
22223}
22224
22225struct CompletionEdit {
22226    new_text: String,
22227    replace_range: Range<usize>,
22228    snippet: Option<Snippet>,
22229}
22230
22231fn insert_extra_newline_brackets(
22232    buffer: &MultiBufferSnapshot,
22233    range: Range<usize>,
22234    language: &language::LanguageScope,
22235) -> bool {
22236    let leading_whitespace_len = buffer
22237        .reversed_chars_at(range.start)
22238        .take_while(|c| c.is_whitespace() && *c != '\n')
22239        .map(|c| c.len_utf8())
22240        .sum::<usize>();
22241    let trailing_whitespace_len = buffer
22242        .chars_at(range.end)
22243        .take_while(|c| c.is_whitespace() && *c != '\n')
22244        .map(|c| c.len_utf8())
22245        .sum::<usize>();
22246    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22247
22248    language.brackets().any(|(pair, enabled)| {
22249        let pair_start = pair.start.trim_end();
22250        let pair_end = pair.end.trim_start();
22251
22252        enabled
22253            && pair.newline
22254            && buffer.contains_str_at(range.end, pair_end)
22255            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22256    })
22257}
22258
22259fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22260    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22261        [(buffer, range, _)] => (*buffer, range.clone()),
22262        _ => return false,
22263    };
22264    let pair = {
22265        let mut result: Option<BracketMatch> = None;
22266
22267        for pair in buffer
22268            .all_bracket_ranges(range.clone())
22269            .filter(move |pair| {
22270                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22271            })
22272        {
22273            let len = pair.close_range.end - pair.open_range.start;
22274
22275            if let Some(existing) = &result {
22276                let existing_len = existing.close_range.end - existing.open_range.start;
22277                if len > existing_len {
22278                    continue;
22279                }
22280            }
22281
22282            result = Some(pair);
22283        }
22284
22285        result
22286    };
22287    let Some(pair) = pair else {
22288        return false;
22289    };
22290    pair.newline_only
22291        && buffer
22292            .chars_for_range(pair.open_range.end..range.start)
22293            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22294            .all(|c| c.is_whitespace() && c != '\n')
22295}
22296
22297fn update_uncommitted_diff_for_buffer(
22298    editor: Entity<Editor>,
22299    project: &Entity<Project>,
22300    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22301    buffer: Entity<MultiBuffer>,
22302    cx: &mut App,
22303) -> Task<()> {
22304    let mut tasks = Vec::new();
22305    project.update(cx, |project, cx| {
22306        for buffer in buffers {
22307            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22308                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22309            }
22310        }
22311    });
22312    cx.spawn(async move |cx| {
22313        let diffs = future::join_all(tasks).await;
22314        if editor
22315            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22316            .unwrap_or(false)
22317        {
22318            return;
22319        }
22320
22321        buffer
22322            .update(cx, |buffer, cx| {
22323                for diff in diffs.into_iter().flatten() {
22324                    buffer.add_diff(diff, cx);
22325                }
22326            })
22327            .ok();
22328    })
22329}
22330
22331fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22332    let tab_size = tab_size.get() as usize;
22333    let mut width = offset;
22334
22335    for ch in text.chars() {
22336        width += if ch == '\t' {
22337            tab_size - (width % tab_size)
22338        } else {
22339            1
22340        };
22341    }
22342
22343    width - offset
22344}
22345
22346#[cfg(test)]
22347mod tests {
22348    use super::*;
22349
22350    #[test]
22351    fn test_string_size_with_expanded_tabs() {
22352        let nz = |val| NonZeroU32::new(val).unwrap();
22353        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22354        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22355        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22356        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22357        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22358        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22359        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22360        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22361    }
22362}
22363
22364/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22365struct WordBreakingTokenizer<'a> {
22366    input: &'a str,
22367}
22368
22369impl<'a> WordBreakingTokenizer<'a> {
22370    fn new(input: &'a str) -> Self {
22371        Self { input }
22372    }
22373}
22374
22375fn is_char_ideographic(ch: char) -> bool {
22376    use unicode_script::Script::*;
22377    use unicode_script::UnicodeScript;
22378    matches!(ch.script(), Han | Tangut | Yi)
22379}
22380
22381fn is_grapheme_ideographic(text: &str) -> bool {
22382    text.chars().any(is_char_ideographic)
22383}
22384
22385fn is_grapheme_whitespace(text: &str) -> bool {
22386    text.chars().any(|x| x.is_whitespace())
22387}
22388
22389fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22390    text.chars()
22391        .next()
22392        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22393}
22394
22395#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22396enum WordBreakToken<'a> {
22397    Word { token: &'a str, grapheme_len: usize },
22398    InlineWhitespace { token: &'a str, grapheme_len: usize },
22399    Newline,
22400}
22401
22402impl<'a> Iterator for WordBreakingTokenizer<'a> {
22403    /// Yields a span, the count of graphemes in the token, and whether it was
22404    /// whitespace. Note that it also breaks at word boundaries.
22405    type Item = WordBreakToken<'a>;
22406
22407    fn next(&mut self) -> Option<Self::Item> {
22408        use unicode_segmentation::UnicodeSegmentation;
22409        if self.input.is_empty() {
22410            return None;
22411        }
22412
22413        let mut iter = self.input.graphemes(true).peekable();
22414        let mut offset = 0;
22415        let mut grapheme_len = 0;
22416        if let Some(first_grapheme) = iter.next() {
22417            let is_newline = first_grapheme == "\n";
22418            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22419            offset += first_grapheme.len();
22420            grapheme_len += 1;
22421            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22422                if let Some(grapheme) = iter.peek().copied()
22423                    && should_stay_with_preceding_ideograph(grapheme)
22424                {
22425                    offset += grapheme.len();
22426                    grapheme_len += 1;
22427                }
22428            } else {
22429                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22430                let mut next_word_bound = words.peek().copied();
22431                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22432                    next_word_bound = words.next();
22433                }
22434                while let Some(grapheme) = iter.peek().copied() {
22435                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22436                        break;
22437                    };
22438                    if is_grapheme_whitespace(grapheme) != is_whitespace
22439                        || (grapheme == "\n") != is_newline
22440                    {
22441                        break;
22442                    };
22443                    offset += grapheme.len();
22444                    grapheme_len += 1;
22445                    iter.next();
22446                }
22447            }
22448            let token = &self.input[..offset];
22449            self.input = &self.input[offset..];
22450            if token == "\n" {
22451                Some(WordBreakToken::Newline)
22452            } else if is_whitespace {
22453                Some(WordBreakToken::InlineWhitespace {
22454                    token,
22455                    grapheme_len,
22456                })
22457            } else {
22458                Some(WordBreakToken::Word {
22459                    token,
22460                    grapheme_len,
22461                })
22462            }
22463        } else {
22464            None
22465        }
22466    }
22467}
22468
22469#[test]
22470fn test_word_breaking_tokenizer() {
22471    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22472        ("", &[]),
22473        ("  ", &[whitespace("  ", 2)]),
22474        ("Ʒ", &[word("Ʒ", 1)]),
22475        ("Ǽ", &[word("Ǽ", 1)]),
22476        ("", &[word("", 1)]),
22477        ("⋑⋑", &[word("⋑⋑", 2)]),
22478        (
22479            "原理,进而",
22480            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22481        ),
22482        (
22483            "hello world",
22484            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22485        ),
22486        (
22487            "hello, world",
22488            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22489        ),
22490        (
22491            "  hello world",
22492            &[
22493                whitespace("  ", 2),
22494                word("hello", 5),
22495                whitespace(" ", 1),
22496                word("world", 5),
22497            ],
22498        ),
22499        (
22500            "这是什么 \n 钢笔",
22501            &[
22502                word("", 1),
22503                word("", 1),
22504                word("", 1),
22505                word("", 1),
22506                whitespace(" ", 1),
22507                newline(),
22508                whitespace(" ", 1),
22509                word("", 1),
22510                word("", 1),
22511            ],
22512        ),
22513        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22514    ];
22515
22516    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22517        WordBreakToken::Word {
22518            token,
22519            grapheme_len,
22520        }
22521    }
22522
22523    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22524        WordBreakToken::InlineWhitespace {
22525            token,
22526            grapheme_len,
22527        }
22528    }
22529
22530    fn newline() -> WordBreakToken<'static> {
22531        WordBreakToken::Newline
22532    }
22533
22534    for (input, result) in tests {
22535        assert_eq!(
22536            WordBreakingTokenizer::new(input)
22537                .collect::<Vec<_>>()
22538                .as_slice(),
22539            *result,
22540        );
22541    }
22542}
22543
22544fn wrap_with_prefix(
22545    first_line_prefix: String,
22546    subsequent_lines_prefix: String,
22547    unwrapped_text: String,
22548    wrap_column: usize,
22549    tab_size: NonZeroU32,
22550    preserve_existing_whitespace: bool,
22551) -> String {
22552    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22553    let subsequent_lines_prefix_len =
22554        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22555    let mut wrapped_text = String::new();
22556    let mut current_line = first_line_prefix;
22557    let mut is_first_line = true;
22558
22559    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22560    let mut current_line_len = first_line_prefix_len;
22561    let mut in_whitespace = false;
22562    for token in tokenizer {
22563        let have_preceding_whitespace = in_whitespace;
22564        match token {
22565            WordBreakToken::Word {
22566                token,
22567                grapheme_len,
22568            } => {
22569                in_whitespace = false;
22570                let current_prefix_len = if is_first_line {
22571                    first_line_prefix_len
22572                } else {
22573                    subsequent_lines_prefix_len
22574                };
22575                if current_line_len + grapheme_len > wrap_column
22576                    && current_line_len != current_prefix_len
22577                {
22578                    wrapped_text.push_str(current_line.trim_end());
22579                    wrapped_text.push('\n');
22580                    is_first_line = false;
22581                    current_line = subsequent_lines_prefix.clone();
22582                    current_line_len = subsequent_lines_prefix_len;
22583                }
22584                current_line.push_str(token);
22585                current_line_len += grapheme_len;
22586            }
22587            WordBreakToken::InlineWhitespace {
22588                mut token,
22589                mut grapheme_len,
22590            } => {
22591                in_whitespace = true;
22592                if have_preceding_whitespace && !preserve_existing_whitespace {
22593                    continue;
22594                }
22595                if !preserve_existing_whitespace {
22596                    // Keep a single whitespace grapheme as-is
22597                    if let Some(first) =
22598                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22599                    {
22600                        token = first;
22601                    } else {
22602                        token = " ";
22603                    }
22604                    grapheme_len = 1;
22605                }
22606                let current_prefix_len = if is_first_line {
22607                    first_line_prefix_len
22608                } else {
22609                    subsequent_lines_prefix_len
22610                };
22611                if current_line_len + grapheme_len > wrap_column {
22612                    wrapped_text.push_str(current_line.trim_end());
22613                    wrapped_text.push('\n');
22614                    is_first_line = false;
22615                    current_line = subsequent_lines_prefix.clone();
22616                    current_line_len = subsequent_lines_prefix_len;
22617                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22618                    current_line.push_str(token);
22619                    current_line_len += grapheme_len;
22620                }
22621            }
22622            WordBreakToken::Newline => {
22623                in_whitespace = true;
22624                let current_prefix_len = if is_first_line {
22625                    first_line_prefix_len
22626                } else {
22627                    subsequent_lines_prefix_len
22628                };
22629                if preserve_existing_whitespace {
22630                    wrapped_text.push_str(current_line.trim_end());
22631                    wrapped_text.push('\n');
22632                    is_first_line = false;
22633                    current_line = subsequent_lines_prefix.clone();
22634                    current_line_len = subsequent_lines_prefix_len;
22635                } else if have_preceding_whitespace {
22636                    continue;
22637                } else if current_line_len + 1 > wrap_column
22638                    && current_line_len != current_prefix_len
22639                {
22640                    wrapped_text.push_str(current_line.trim_end());
22641                    wrapped_text.push('\n');
22642                    is_first_line = false;
22643                    current_line = subsequent_lines_prefix.clone();
22644                    current_line_len = subsequent_lines_prefix_len;
22645                } else if current_line_len != current_prefix_len {
22646                    current_line.push(' ');
22647                    current_line_len += 1;
22648                }
22649            }
22650        }
22651    }
22652
22653    if !current_line.is_empty() {
22654        wrapped_text.push_str(&current_line);
22655    }
22656    wrapped_text
22657}
22658
22659#[test]
22660fn test_wrap_with_prefix() {
22661    assert_eq!(
22662        wrap_with_prefix(
22663            "# ".to_string(),
22664            "# ".to_string(),
22665            "abcdefg".to_string(),
22666            4,
22667            NonZeroU32::new(4).unwrap(),
22668            false,
22669        ),
22670        "# abcdefg"
22671    );
22672    assert_eq!(
22673        wrap_with_prefix(
22674            "".to_string(),
22675            "".to_string(),
22676            "\thello world".to_string(),
22677            8,
22678            NonZeroU32::new(4).unwrap(),
22679            false,
22680        ),
22681        "hello\nworld"
22682    );
22683    assert_eq!(
22684        wrap_with_prefix(
22685            "// ".to_string(),
22686            "// ".to_string(),
22687            "xx \nyy zz aa bb cc".to_string(),
22688            12,
22689            NonZeroU32::new(4).unwrap(),
22690            false,
22691        ),
22692        "// xx yy zz\n// aa bb cc"
22693    );
22694    assert_eq!(
22695        wrap_with_prefix(
22696            String::new(),
22697            String::new(),
22698            "这是什么 \n 钢笔".to_string(),
22699            3,
22700            NonZeroU32::new(4).unwrap(),
22701            false,
22702        ),
22703        "这是什\n么 钢\n"
22704    );
22705    assert_eq!(
22706        wrap_with_prefix(
22707            String::new(),
22708            String::new(),
22709            format!("foo{}bar", '\u{2009}'), // thin space
22710            80,
22711            NonZeroU32::new(4).unwrap(),
22712            false,
22713        ),
22714        format!("foo{}bar", '\u{2009}')
22715    );
22716}
22717
22718pub trait CollaborationHub {
22719    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22720    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22721    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22722}
22723
22724impl CollaborationHub for Entity<Project> {
22725    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22726        self.read(cx).collaborators()
22727    }
22728
22729    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22730        self.read(cx).user_store().read(cx).participant_indices()
22731    }
22732
22733    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22734        let this = self.read(cx);
22735        let user_ids = this.collaborators().values().map(|c| c.user_id);
22736        this.user_store().read(cx).participant_names(user_ids, cx)
22737    }
22738}
22739
22740pub trait SemanticsProvider {
22741    fn hover(
22742        &self,
22743        buffer: &Entity<Buffer>,
22744        position: text::Anchor,
22745        cx: &mut App,
22746    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22747
22748    fn inline_values(
22749        &self,
22750        buffer_handle: Entity<Buffer>,
22751        range: Range<text::Anchor>,
22752        cx: &mut App,
22753    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22754
22755    fn inlay_hints(
22756        &self,
22757        buffer_handle: Entity<Buffer>,
22758        range: Range<text::Anchor>,
22759        cx: &mut App,
22760    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22761
22762    fn resolve_inlay_hint(
22763        &self,
22764        hint: InlayHint,
22765        buffer_handle: Entity<Buffer>,
22766        server_id: LanguageServerId,
22767        cx: &mut App,
22768    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22769
22770    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22771
22772    fn document_highlights(
22773        &self,
22774        buffer: &Entity<Buffer>,
22775        position: text::Anchor,
22776        cx: &mut App,
22777    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22778
22779    fn definitions(
22780        &self,
22781        buffer: &Entity<Buffer>,
22782        position: text::Anchor,
22783        kind: GotoDefinitionKind,
22784        cx: &mut App,
22785    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22786
22787    fn range_for_rename(
22788        &self,
22789        buffer: &Entity<Buffer>,
22790        position: text::Anchor,
22791        cx: &mut App,
22792    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22793
22794    fn perform_rename(
22795        &self,
22796        buffer: &Entity<Buffer>,
22797        position: text::Anchor,
22798        new_name: String,
22799        cx: &mut App,
22800    ) -> Option<Task<Result<ProjectTransaction>>>;
22801}
22802
22803pub trait CompletionProvider {
22804    fn completions(
22805        &self,
22806        excerpt_id: ExcerptId,
22807        buffer: &Entity<Buffer>,
22808        buffer_position: text::Anchor,
22809        trigger: CompletionContext,
22810        window: &mut Window,
22811        cx: &mut Context<Editor>,
22812    ) -> Task<Result<Vec<CompletionResponse>>>;
22813
22814    fn resolve_completions(
22815        &self,
22816        _buffer: Entity<Buffer>,
22817        _completion_indices: Vec<usize>,
22818        _completions: Rc<RefCell<Box<[Completion]>>>,
22819        _cx: &mut Context<Editor>,
22820    ) -> Task<Result<bool>> {
22821        Task::ready(Ok(false))
22822    }
22823
22824    fn apply_additional_edits_for_completion(
22825        &self,
22826        _buffer: Entity<Buffer>,
22827        _completions: Rc<RefCell<Box<[Completion]>>>,
22828        _completion_index: usize,
22829        _push_to_history: bool,
22830        _cx: &mut Context<Editor>,
22831    ) -> Task<Result<Option<language::Transaction>>> {
22832        Task::ready(Ok(None))
22833    }
22834
22835    fn is_completion_trigger(
22836        &self,
22837        buffer: &Entity<Buffer>,
22838        position: language::Anchor,
22839        text: &str,
22840        trigger_in_words: bool,
22841        menu_is_open: bool,
22842        cx: &mut Context<Editor>,
22843    ) -> bool;
22844
22845    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22846
22847    fn sort_completions(&self) -> bool {
22848        true
22849    }
22850
22851    fn filter_completions(&self) -> bool {
22852        true
22853    }
22854}
22855
22856pub trait CodeActionProvider {
22857    fn id(&self) -> Arc<str>;
22858
22859    fn code_actions(
22860        &self,
22861        buffer: &Entity<Buffer>,
22862        range: Range<text::Anchor>,
22863        window: &mut Window,
22864        cx: &mut App,
22865    ) -> Task<Result<Vec<CodeAction>>>;
22866
22867    fn apply_code_action(
22868        &self,
22869        buffer_handle: Entity<Buffer>,
22870        action: CodeAction,
22871        excerpt_id: ExcerptId,
22872        push_to_history: bool,
22873        window: &mut Window,
22874        cx: &mut App,
22875    ) -> Task<Result<ProjectTransaction>>;
22876}
22877
22878impl CodeActionProvider for Entity<Project> {
22879    fn id(&self) -> Arc<str> {
22880        "project".into()
22881    }
22882
22883    fn code_actions(
22884        &self,
22885        buffer: &Entity<Buffer>,
22886        range: Range<text::Anchor>,
22887        _window: &mut Window,
22888        cx: &mut App,
22889    ) -> Task<Result<Vec<CodeAction>>> {
22890        self.update(cx, |project, cx| {
22891            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22892            let code_actions = project.code_actions(buffer, range, None, cx);
22893            cx.background_spawn(async move {
22894                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22895                Ok(code_lens_actions
22896                    .context("code lens fetch")?
22897                    .into_iter()
22898                    .flatten()
22899                    .chain(
22900                        code_actions
22901                            .context("code action fetch")?
22902                            .into_iter()
22903                            .flatten(),
22904                    )
22905                    .collect())
22906            })
22907        })
22908    }
22909
22910    fn apply_code_action(
22911        &self,
22912        buffer_handle: Entity<Buffer>,
22913        action: CodeAction,
22914        _excerpt_id: ExcerptId,
22915        push_to_history: bool,
22916        _window: &mut Window,
22917        cx: &mut App,
22918    ) -> Task<Result<ProjectTransaction>> {
22919        self.update(cx, |project, cx| {
22920            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22921        })
22922    }
22923}
22924
22925fn snippet_completions(
22926    project: &Project,
22927    buffer: &Entity<Buffer>,
22928    buffer_position: text::Anchor,
22929    cx: &mut App,
22930) -> Task<Result<CompletionResponse>> {
22931    let languages = buffer.read(cx).languages_at(buffer_position);
22932    let snippet_store = project.snippets().read(cx);
22933
22934    let scopes: Vec<_> = languages
22935        .iter()
22936        .filter_map(|language| {
22937            let language_name = language.lsp_id();
22938            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22939
22940            if snippets.is_empty() {
22941                None
22942            } else {
22943                Some((language.default_scope(), snippets))
22944            }
22945        })
22946        .collect();
22947
22948    if scopes.is_empty() {
22949        return Task::ready(Ok(CompletionResponse {
22950            completions: vec![],
22951            display_options: CompletionDisplayOptions::default(),
22952            is_incomplete: false,
22953        }));
22954    }
22955
22956    let snapshot = buffer.read(cx).text_snapshot();
22957    let executor = cx.background_executor().clone();
22958
22959    cx.background_spawn(async move {
22960        let mut is_incomplete = false;
22961        let mut completions: Vec<Completion> = Vec::new();
22962        for (scope, snippets) in scopes.into_iter() {
22963            let classifier =
22964                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22965
22966            const MAX_WORD_PREFIX_LEN: usize = 128;
22967            let last_word: String = snapshot
22968                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22969                .take(MAX_WORD_PREFIX_LEN)
22970                .take_while(|c| classifier.is_word(*c))
22971                .collect::<String>()
22972                .chars()
22973                .rev()
22974                .collect();
22975
22976            if last_word.is_empty() {
22977                return Ok(CompletionResponse {
22978                    completions: vec![],
22979                    display_options: CompletionDisplayOptions::default(),
22980                    is_incomplete: true,
22981                });
22982            }
22983
22984            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22985            let to_lsp = |point: &text::Anchor| {
22986                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22987                point_to_lsp(end)
22988            };
22989            let lsp_end = to_lsp(&buffer_position);
22990
22991            let candidates = snippets
22992                .iter()
22993                .enumerate()
22994                .flat_map(|(ix, snippet)| {
22995                    snippet
22996                        .prefix
22997                        .iter()
22998                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22999                })
23000                .collect::<Vec<StringMatchCandidate>>();
23001
23002            const MAX_RESULTS: usize = 100;
23003            let mut matches = fuzzy::match_strings(
23004                &candidates,
23005                &last_word,
23006                last_word.chars().any(|c| c.is_uppercase()),
23007                true,
23008                MAX_RESULTS,
23009                &Default::default(),
23010                executor.clone(),
23011            )
23012            .await;
23013
23014            if matches.len() >= MAX_RESULTS {
23015                is_incomplete = true;
23016            }
23017
23018            // Remove all candidates where the query's start does not match the start of any word in the candidate
23019            if let Some(query_start) = last_word.chars().next() {
23020                matches.retain(|string_match| {
23021                    split_words(&string_match.string).any(|word| {
23022                        // Check that the first codepoint of the word as lowercase matches the first
23023                        // codepoint of the query as lowercase
23024                        word.chars()
23025                            .flat_map(|codepoint| codepoint.to_lowercase())
23026                            .zip(query_start.to_lowercase())
23027                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23028                    })
23029                });
23030            }
23031
23032            let matched_strings = matches
23033                .into_iter()
23034                .map(|m| m.string)
23035                .collect::<HashSet<_>>();
23036
23037            completions.extend(snippets.iter().filter_map(|snippet| {
23038                let matching_prefix = snippet
23039                    .prefix
23040                    .iter()
23041                    .find(|prefix| matched_strings.contains(*prefix))?;
23042                let start = as_offset - last_word.len();
23043                let start = snapshot.anchor_before(start);
23044                let range = start..buffer_position;
23045                let lsp_start = to_lsp(&start);
23046                let lsp_range = lsp::Range {
23047                    start: lsp_start,
23048                    end: lsp_end,
23049                };
23050                Some(Completion {
23051                    replace_range: range,
23052                    new_text: snippet.body.clone(),
23053                    source: CompletionSource::Lsp {
23054                        insert_range: None,
23055                        server_id: LanguageServerId(usize::MAX),
23056                        resolved: true,
23057                        lsp_completion: Box::new(lsp::CompletionItem {
23058                            label: snippet.prefix.first().unwrap().clone(),
23059                            kind: Some(CompletionItemKind::SNIPPET),
23060                            label_details: snippet.description.as_ref().map(|description| {
23061                                lsp::CompletionItemLabelDetails {
23062                                    detail: Some(description.clone()),
23063                                    description: None,
23064                                }
23065                            }),
23066                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23067                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23068                                lsp::InsertReplaceEdit {
23069                                    new_text: snippet.body.clone(),
23070                                    insert: lsp_range,
23071                                    replace: lsp_range,
23072                                },
23073                            )),
23074                            filter_text: Some(snippet.body.clone()),
23075                            sort_text: Some(char::MAX.to_string()),
23076                            ..lsp::CompletionItem::default()
23077                        }),
23078                        lsp_defaults: None,
23079                    },
23080                    label: CodeLabel {
23081                        text: matching_prefix.clone(),
23082                        runs: Vec::new(),
23083                        filter_range: 0..matching_prefix.len(),
23084                    },
23085                    icon_path: None,
23086                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23087                        single_line: snippet.name.clone().into(),
23088                        plain_text: snippet
23089                            .description
23090                            .clone()
23091                            .map(|description| description.into()),
23092                    }),
23093                    insert_text_mode: None,
23094                    confirm: None,
23095                })
23096            }))
23097        }
23098
23099        Ok(CompletionResponse {
23100            completions,
23101            display_options: CompletionDisplayOptions::default(),
23102            is_incomplete,
23103        })
23104    })
23105}
23106
23107impl CompletionProvider for Entity<Project> {
23108    fn completions(
23109        &self,
23110        _excerpt_id: ExcerptId,
23111        buffer: &Entity<Buffer>,
23112        buffer_position: text::Anchor,
23113        options: CompletionContext,
23114        _window: &mut Window,
23115        cx: &mut Context<Editor>,
23116    ) -> Task<Result<Vec<CompletionResponse>>> {
23117        self.update(cx, |project, cx| {
23118            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23119            let project_completions = project.completions(buffer, buffer_position, options, cx);
23120            cx.background_spawn(async move {
23121                let mut responses = project_completions.await?;
23122                let snippets = snippets.await?;
23123                if !snippets.completions.is_empty() {
23124                    responses.push(snippets);
23125                }
23126                Ok(responses)
23127            })
23128        })
23129    }
23130
23131    fn resolve_completions(
23132        &self,
23133        buffer: Entity<Buffer>,
23134        completion_indices: Vec<usize>,
23135        completions: Rc<RefCell<Box<[Completion]>>>,
23136        cx: &mut Context<Editor>,
23137    ) -> Task<Result<bool>> {
23138        self.update(cx, |project, cx| {
23139            project.lsp_store().update(cx, |lsp_store, cx| {
23140                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23141            })
23142        })
23143    }
23144
23145    fn apply_additional_edits_for_completion(
23146        &self,
23147        buffer: Entity<Buffer>,
23148        completions: Rc<RefCell<Box<[Completion]>>>,
23149        completion_index: usize,
23150        push_to_history: bool,
23151        cx: &mut Context<Editor>,
23152    ) -> Task<Result<Option<language::Transaction>>> {
23153        self.update(cx, |project, cx| {
23154            project.lsp_store().update(cx, |lsp_store, cx| {
23155                lsp_store.apply_additional_edits_for_completion(
23156                    buffer,
23157                    completions,
23158                    completion_index,
23159                    push_to_history,
23160                    cx,
23161                )
23162            })
23163        })
23164    }
23165
23166    fn is_completion_trigger(
23167        &self,
23168        buffer: &Entity<Buffer>,
23169        position: language::Anchor,
23170        text: &str,
23171        trigger_in_words: bool,
23172        menu_is_open: bool,
23173        cx: &mut Context<Editor>,
23174    ) -> bool {
23175        let mut chars = text.chars();
23176        let char = if let Some(char) = chars.next() {
23177            char
23178        } else {
23179            return false;
23180        };
23181        if chars.next().is_some() {
23182            return false;
23183        }
23184
23185        let buffer = buffer.read(cx);
23186        let snapshot = buffer.snapshot();
23187        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23188            return false;
23189        }
23190        let classifier = snapshot
23191            .char_classifier_at(position)
23192            .scope_context(Some(CharScopeContext::Completion));
23193        if trigger_in_words && classifier.is_word(char) {
23194            return true;
23195        }
23196
23197        buffer.completion_triggers().contains(text)
23198    }
23199}
23200
23201impl SemanticsProvider for Entity<Project> {
23202    fn hover(
23203        &self,
23204        buffer: &Entity<Buffer>,
23205        position: text::Anchor,
23206        cx: &mut App,
23207    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23208        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23209    }
23210
23211    fn document_highlights(
23212        &self,
23213        buffer: &Entity<Buffer>,
23214        position: text::Anchor,
23215        cx: &mut App,
23216    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23217        Some(self.update(cx, |project, cx| {
23218            project.document_highlights(buffer, position, cx)
23219        }))
23220    }
23221
23222    fn definitions(
23223        &self,
23224        buffer: &Entity<Buffer>,
23225        position: text::Anchor,
23226        kind: GotoDefinitionKind,
23227        cx: &mut App,
23228    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23229        Some(self.update(cx, |project, cx| match kind {
23230            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23231            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23232            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23233            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23234        }))
23235    }
23236
23237    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23238        self.update(cx, |project, cx| {
23239            if project
23240                .active_debug_session(cx)
23241                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23242            {
23243                return true;
23244            }
23245
23246            buffer.update(cx, |buffer, cx| {
23247                project.any_language_server_supports_inlay_hints(buffer, cx)
23248            })
23249        })
23250    }
23251
23252    fn inline_values(
23253        &self,
23254        buffer_handle: Entity<Buffer>,
23255        range: Range<text::Anchor>,
23256        cx: &mut App,
23257    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23258        self.update(cx, |project, cx| {
23259            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23260
23261            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23262        })
23263    }
23264
23265    fn inlay_hints(
23266        &self,
23267        buffer_handle: Entity<Buffer>,
23268        range: Range<text::Anchor>,
23269        cx: &mut App,
23270    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23271        Some(self.update(cx, |project, cx| {
23272            project.inlay_hints(buffer_handle, range, cx)
23273        }))
23274    }
23275
23276    fn resolve_inlay_hint(
23277        &self,
23278        hint: InlayHint,
23279        buffer_handle: Entity<Buffer>,
23280        server_id: LanguageServerId,
23281        cx: &mut App,
23282    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23283        Some(self.update(cx, |project, cx| {
23284            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23285        }))
23286    }
23287
23288    fn range_for_rename(
23289        &self,
23290        buffer: &Entity<Buffer>,
23291        position: text::Anchor,
23292        cx: &mut App,
23293    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23294        Some(self.update(cx, |project, cx| {
23295            let buffer = buffer.clone();
23296            let task = project.prepare_rename(buffer.clone(), position, cx);
23297            cx.spawn(async move |_, cx| {
23298                Ok(match task.await? {
23299                    PrepareRenameResponse::Success(range) => Some(range),
23300                    PrepareRenameResponse::InvalidPosition => None,
23301                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23302                        // Fallback on using TreeSitter info to determine identifier range
23303                        buffer.read_with(cx, |buffer, _| {
23304                            let snapshot = buffer.snapshot();
23305                            let (range, kind) = snapshot.surrounding_word(position, None);
23306                            if kind != Some(CharKind::Word) {
23307                                return None;
23308                            }
23309                            Some(
23310                                snapshot.anchor_before(range.start)
23311                                    ..snapshot.anchor_after(range.end),
23312                            )
23313                        })?
23314                    }
23315                })
23316            })
23317        }))
23318    }
23319
23320    fn perform_rename(
23321        &self,
23322        buffer: &Entity<Buffer>,
23323        position: text::Anchor,
23324        new_name: String,
23325        cx: &mut App,
23326    ) -> Option<Task<Result<ProjectTransaction>>> {
23327        Some(self.update(cx, |project, cx| {
23328            project.perform_rename(buffer.clone(), position, new_name, cx)
23329        }))
23330    }
23331}
23332
23333fn inlay_hint_settings(
23334    location: Anchor,
23335    snapshot: &MultiBufferSnapshot,
23336    cx: &mut Context<Editor>,
23337) -> InlayHintSettings {
23338    let file = snapshot.file_at(location);
23339    let language = snapshot.language_at(location).map(|l| l.name());
23340    language_settings(language, file, cx).inlay_hints
23341}
23342
23343fn consume_contiguous_rows(
23344    contiguous_row_selections: &mut Vec<Selection<Point>>,
23345    selection: &Selection<Point>,
23346    display_map: &DisplaySnapshot,
23347    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23348) -> (MultiBufferRow, MultiBufferRow) {
23349    contiguous_row_selections.push(selection.clone());
23350    let start_row = starting_row(selection, display_map);
23351    let mut end_row = ending_row(selection, display_map);
23352
23353    while let Some(next_selection) = selections.peek() {
23354        if next_selection.start.row <= end_row.0 {
23355            end_row = ending_row(next_selection, display_map);
23356            contiguous_row_selections.push(selections.next().unwrap().clone());
23357        } else {
23358            break;
23359        }
23360    }
23361    (start_row, end_row)
23362}
23363
23364fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23365    if selection.start.column > 0 {
23366        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23367    } else {
23368        MultiBufferRow(selection.start.row)
23369    }
23370}
23371
23372fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23373    if next_selection.end.column > 0 || next_selection.is_empty() {
23374        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23375    } else {
23376        MultiBufferRow(next_selection.end.row)
23377    }
23378}
23379
23380impl EditorSnapshot {
23381    pub fn remote_selections_in_range<'a>(
23382        &'a self,
23383        range: &'a Range<Anchor>,
23384        collaboration_hub: &dyn CollaborationHub,
23385        cx: &'a App,
23386    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23387        let participant_names = collaboration_hub.user_names(cx);
23388        let participant_indices = collaboration_hub.user_participant_indices(cx);
23389        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23390        let collaborators_by_replica_id = collaborators_by_peer_id
23391            .values()
23392            .map(|collaborator| (collaborator.replica_id, collaborator))
23393            .collect::<HashMap<_, _>>();
23394        self.buffer_snapshot()
23395            .selections_in_range(range, false)
23396            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23397                if replica_id == AGENT_REPLICA_ID {
23398                    Some(RemoteSelection {
23399                        replica_id,
23400                        selection,
23401                        cursor_shape,
23402                        line_mode,
23403                        collaborator_id: CollaboratorId::Agent,
23404                        user_name: Some("Agent".into()),
23405                        color: cx.theme().players().agent(),
23406                    })
23407                } else {
23408                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23409                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23410                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23411                    Some(RemoteSelection {
23412                        replica_id,
23413                        selection,
23414                        cursor_shape,
23415                        line_mode,
23416                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23417                        user_name,
23418                        color: if let Some(index) = participant_index {
23419                            cx.theme().players().color_for_participant(index.0)
23420                        } else {
23421                            cx.theme().players().absent()
23422                        },
23423                    })
23424                }
23425            })
23426    }
23427
23428    pub fn hunks_for_ranges(
23429        &self,
23430        ranges: impl IntoIterator<Item = Range<Point>>,
23431    ) -> Vec<MultiBufferDiffHunk> {
23432        let mut hunks = Vec::new();
23433        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23434            HashMap::default();
23435        for query_range in ranges {
23436            let query_rows =
23437                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23438            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23439                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23440            ) {
23441                // Include deleted hunks that are adjacent to the query range, because
23442                // otherwise they would be missed.
23443                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23444                if hunk.status().is_deleted() {
23445                    intersects_range |= hunk.row_range.start == query_rows.end;
23446                    intersects_range |= hunk.row_range.end == query_rows.start;
23447                }
23448                if intersects_range {
23449                    if !processed_buffer_rows
23450                        .entry(hunk.buffer_id)
23451                        .or_default()
23452                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23453                    {
23454                        continue;
23455                    }
23456                    hunks.push(hunk);
23457                }
23458            }
23459        }
23460
23461        hunks
23462    }
23463
23464    fn display_diff_hunks_for_rows<'a>(
23465        &'a self,
23466        display_rows: Range<DisplayRow>,
23467        folded_buffers: &'a HashSet<BufferId>,
23468    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23469        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23470        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23471
23472        self.buffer_snapshot()
23473            .diff_hunks_in_range(buffer_start..buffer_end)
23474            .filter_map(|hunk| {
23475                if folded_buffers.contains(&hunk.buffer_id) {
23476                    return None;
23477                }
23478
23479                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23480                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23481
23482                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23483                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23484
23485                let display_hunk = if hunk_display_start.column() != 0 {
23486                    DisplayDiffHunk::Folded {
23487                        display_row: hunk_display_start.row(),
23488                    }
23489                } else {
23490                    let mut end_row = hunk_display_end.row();
23491                    if hunk_display_end.column() > 0 {
23492                        end_row.0 += 1;
23493                    }
23494                    let is_created_file = hunk.is_created_file();
23495                    DisplayDiffHunk::Unfolded {
23496                        status: hunk.status(),
23497                        diff_base_byte_range: hunk.diff_base_byte_range,
23498                        display_row_range: hunk_display_start.row()..end_row,
23499                        multi_buffer_range: Anchor::range_in_buffer(
23500                            hunk.excerpt_id,
23501                            hunk.buffer_id,
23502                            hunk.buffer_range,
23503                        ),
23504                        is_created_file,
23505                    }
23506                };
23507
23508                Some(display_hunk)
23509            })
23510    }
23511
23512    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23513        self.display_snapshot
23514            .buffer_snapshot()
23515            .language_at(position)
23516    }
23517
23518    pub fn is_focused(&self) -> bool {
23519        self.is_focused
23520    }
23521
23522    pub fn placeholder_text(&self) -> Option<String> {
23523        self.placeholder_display_snapshot
23524            .as_ref()
23525            .map(|display_map| display_map.text())
23526    }
23527
23528    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23529        self.scroll_anchor.scroll_position(&self.display_snapshot)
23530    }
23531
23532    fn gutter_dimensions(
23533        &self,
23534        font_id: FontId,
23535        font_size: Pixels,
23536        max_line_number_width: Pixels,
23537        cx: &App,
23538    ) -> Option<GutterDimensions> {
23539        if !self.show_gutter {
23540            return None;
23541        }
23542
23543        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23544        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23545
23546        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23547            matches!(
23548                ProjectSettings::get_global(cx).git.git_gutter,
23549                GitGutterSetting::TrackedFiles
23550            )
23551        });
23552        let gutter_settings = EditorSettings::get_global(cx).gutter;
23553        let show_line_numbers = self
23554            .show_line_numbers
23555            .unwrap_or(gutter_settings.line_numbers);
23556        let line_gutter_width = if show_line_numbers {
23557            // Avoid flicker-like gutter resizes when the line number gains another digit by
23558            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23559            let min_width_for_number_on_gutter =
23560                ch_advance * gutter_settings.min_line_number_digits as f32;
23561            max_line_number_width.max(min_width_for_number_on_gutter)
23562        } else {
23563            0.0.into()
23564        };
23565
23566        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23567        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23568
23569        let git_blame_entries_width =
23570            self.git_blame_gutter_max_author_length
23571                .map(|max_author_length| {
23572                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23573                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23574
23575                    /// The number of characters to dedicate to gaps and margins.
23576                    const SPACING_WIDTH: usize = 4;
23577
23578                    let max_char_count = max_author_length.min(renderer.max_author_length())
23579                        + ::git::SHORT_SHA_LENGTH
23580                        + MAX_RELATIVE_TIMESTAMP.len()
23581                        + SPACING_WIDTH;
23582
23583                    ch_advance * max_char_count
23584                });
23585
23586        let is_singleton = self.buffer_snapshot().is_singleton();
23587
23588        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23589        left_padding += if !is_singleton {
23590            ch_width * 4.0
23591        } else if show_runnables || show_breakpoints {
23592            ch_width * 3.0
23593        } else if show_git_gutter && show_line_numbers {
23594            ch_width * 2.0
23595        } else if show_git_gutter || show_line_numbers {
23596            ch_width
23597        } else {
23598            px(0.)
23599        };
23600
23601        let shows_folds = is_singleton && gutter_settings.folds;
23602
23603        let right_padding = if shows_folds && show_line_numbers {
23604            ch_width * 4.0
23605        } else if shows_folds || (!is_singleton && show_line_numbers) {
23606            ch_width * 3.0
23607        } else if show_line_numbers {
23608            ch_width
23609        } else {
23610            px(0.)
23611        };
23612
23613        Some(GutterDimensions {
23614            left_padding,
23615            right_padding,
23616            width: line_gutter_width + left_padding + right_padding,
23617            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23618            git_blame_entries_width,
23619        })
23620    }
23621
23622    pub fn render_crease_toggle(
23623        &self,
23624        buffer_row: MultiBufferRow,
23625        row_contains_cursor: bool,
23626        editor: Entity<Editor>,
23627        window: &mut Window,
23628        cx: &mut App,
23629    ) -> Option<AnyElement> {
23630        let folded = self.is_line_folded(buffer_row);
23631        let mut is_foldable = false;
23632
23633        if let Some(crease) = self
23634            .crease_snapshot
23635            .query_row(buffer_row, self.buffer_snapshot())
23636        {
23637            is_foldable = true;
23638            match crease {
23639                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23640                    if let Some(render_toggle) = render_toggle {
23641                        let toggle_callback =
23642                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23643                                if folded {
23644                                    editor.update(cx, |editor, cx| {
23645                                        editor.fold_at(buffer_row, window, cx)
23646                                    });
23647                                } else {
23648                                    editor.update(cx, |editor, cx| {
23649                                        editor.unfold_at(buffer_row, window, cx)
23650                                    });
23651                                }
23652                            });
23653                        return Some((render_toggle)(
23654                            buffer_row,
23655                            folded,
23656                            toggle_callback,
23657                            window,
23658                            cx,
23659                        ));
23660                    }
23661                }
23662            }
23663        }
23664
23665        is_foldable |= self.starts_indent(buffer_row);
23666
23667        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23668            Some(
23669                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23670                    .toggle_state(folded)
23671                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23672                        if folded {
23673                            this.unfold_at(buffer_row, window, cx);
23674                        } else {
23675                            this.fold_at(buffer_row, window, cx);
23676                        }
23677                    }))
23678                    .into_any_element(),
23679            )
23680        } else {
23681            None
23682        }
23683    }
23684
23685    pub fn render_crease_trailer(
23686        &self,
23687        buffer_row: MultiBufferRow,
23688        window: &mut Window,
23689        cx: &mut App,
23690    ) -> Option<AnyElement> {
23691        let folded = self.is_line_folded(buffer_row);
23692        if let Crease::Inline { render_trailer, .. } = self
23693            .crease_snapshot
23694            .query_row(buffer_row, self.buffer_snapshot())?
23695        {
23696            let render_trailer = render_trailer.as_ref()?;
23697            Some(render_trailer(buffer_row, folded, window, cx))
23698        } else {
23699            None
23700        }
23701    }
23702}
23703
23704impl Deref for EditorSnapshot {
23705    type Target = DisplaySnapshot;
23706
23707    fn deref(&self) -> &Self::Target {
23708        &self.display_snapshot
23709    }
23710}
23711
23712#[derive(Clone, Debug, PartialEq, Eq)]
23713pub enum EditorEvent {
23714    InputIgnored {
23715        text: Arc<str>,
23716    },
23717    InputHandled {
23718        utf16_range_to_replace: Option<Range<isize>>,
23719        text: Arc<str>,
23720    },
23721    ExcerptsAdded {
23722        buffer: Entity<Buffer>,
23723        predecessor: ExcerptId,
23724        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23725    },
23726    ExcerptsRemoved {
23727        ids: Vec<ExcerptId>,
23728        removed_buffer_ids: Vec<BufferId>,
23729    },
23730    BufferFoldToggled {
23731        ids: Vec<ExcerptId>,
23732        folded: bool,
23733    },
23734    ExcerptsEdited {
23735        ids: Vec<ExcerptId>,
23736    },
23737    ExcerptsExpanded {
23738        ids: Vec<ExcerptId>,
23739    },
23740    BufferEdited,
23741    Edited {
23742        transaction_id: clock::Lamport,
23743    },
23744    Reparsed(BufferId),
23745    Focused,
23746    FocusedIn,
23747    Blurred,
23748    DirtyChanged,
23749    Saved,
23750    TitleChanged,
23751    SelectionsChanged {
23752        local: bool,
23753    },
23754    ScrollPositionChanged {
23755        local: bool,
23756        autoscroll: bool,
23757    },
23758    TransactionUndone {
23759        transaction_id: clock::Lamport,
23760    },
23761    TransactionBegun {
23762        transaction_id: clock::Lamport,
23763    },
23764    CursorShapeChanged,
23765    BreadcrumbsChanged,
23766    PushedToNavHistory {
23767        anchor: Anchor,
23768        is_deactivate: bool,
23769    },
23770}
23771
23772impl EventEmitter<EditorEvent> for Editor {}
23773
23774impl Focusable for Editor {
23775    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23776        self.focus_handle.clone()
23777    }
23778}
23779
23780impl Render for Editor {
23781    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23782        let settings = ThemeSettings::get_global(cx);
23783
23784        let mut text_style = match self.mode {
23785            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23786                color: cx.theme().colors().editor_foreground,
23787                font_family: settings.ui_font.family.clone(),
23788                font_features: settings.ui_font.features.clone(),
23789                font_fallbacks: settings.ui_font.fallbacks.clone(),
23790                font_size: rems(0.875).into(),
23791                font_weight: settings.ui_font.weight,
23792                line_height: relative(settings.buffer_line_height.value()),
23793                ..Default::default()
23794            },
23795            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23796                color: cx.theme().colors().editor_foreground,
23797                font_family: settings.buffer_font.family.clone(),
23798                font_features: settings.buffer_font.features.clone(),
23799                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23800                font_size: settings.buffer_font_size(cx).into(),
23801                font_weight: settings.buffer_font.weight,
23802                line_height: relative(settings.buffer_line_height.value()),
23803                ..Default::default()
23804            },
23805        };
23806        if let Some(text_style_refinement) = &self.text_style_refinement {
23807            text_style.refine(text_style_refinement)
23808        }
23809
23810        let background = match self.mode {
23811            EditorMode::SingleLine => cx.theme().system().transparent,
23812            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23813            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23814            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23815        };
23816
23817        EditorElement::new(
23818            &cx.entity(),
23819            EditorStyle {
23820                background,
23821                border: cx.theme().colors().border,
23822                local_player: cx.theme().players().local(),
23823                text: text_style,
23824                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23825                syntax: cx.theme().syntax().clone(),
23826                status: cx.theme().status().clone(),
23827                inlay_hints_style: make_inlay_hints_style(cx),
23828                edit_prediction_styles: make_suggestion_styles(cx),
23829                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23830                show_underlines: self.diagnostics_enabled(),
23831            },
23832        )
23833    }
23834}
23835
23836impl EntityInputHandler for Editor {
23837    fn text_for_range(
23838        &mut self,
23839        range_utf16: Range<usize>,
23840        adjusted_range: &mut Option<Range<usize>>,
23841        _: &mut Window,
23842        cx: &mut Context<Self>,
23843    ) -> Option<String> {
23844        let snapshot = self.buffer.read(cx).read(cx);
23845        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23846        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23847        if (start.0..end.0) != range_utf16 {
23848            adjusted_range.replace(start.0..end.0);
23849        }
23850        Some(snapshot.text_for_range(start..end).collect())
23851    }
23852
23853    fn selected_text_range(
23854        &mut self,
23855        ignore_disabled_input: bool,
23856        _: &mut Window,
23857        cx: &mut Context<Self>,
23858    ) -> Option<UTF16Selection> {
23859        // Prevent the IME menu from appearing when holding down an alphabetic key
23860        // while input is disabled.
23861        if !ignore_disabled_input && !self.input_enabled {
23862            return None;
23863        }
23864
23865        let selection = self.selections.newest::<OffsetUtf16>(cx);
23866        let range = selection.range();
23867
23868        Some(UTF16Selection {
23869            range: range.start.0..range.end.0,
23870            reversed: selection.reversed,
23871        })
23872    }
23873
23874    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23875        let snapshot = self.buffer.read(cx).read(cx);
23876        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23877        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23878    }
23879
23880    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23881        self.clear_highlights::<InputComposition>(cx);
23882        self.ime_transaction.take();
23883    }
23884
23885    fn replace_text_in_range(
23886        &mut self,
23887        range_utf16: Option<Range<usize>>,
23888        text: &str,
23889        window: &mut Window,
23890        cx: &mut Context<Self>,
23891    ) {
23892        if !self.input_enabled {
23893            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23894            return;
23895        }
23896
23897        self.transact(window, cx, |this, window, cx| {
23898            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23899                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23900                Some(this.selection_replacement_ranges(range_utf16, cx))
23901            } else {
23902                this.marked_text_ranges(cx)
23903            };
23904
23905            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23906                let newest_selection_id = this.selections.newest_anchor().id;
23907                this.selections
23908                    .all::<OffsetUtf16>(cx)
23909                    .iter()
23910                    .zip(ranges_to_replace.iter())
23911                    .find_map(|(selection, range)| {
23912                        if selection.id == newest_selection_id {
23913                            Some(
23914                                (range.start.0 as isize - selection.head().0 as isize)
23915                                    ..(range.end.0 as isize - selection.head().0 as isize),
23916                            )
23917                        } else {
23918                            None
23919                        }
23920                    })
23921            });
23922
23923            cx.emit(EditorEvent::InputHandled {
23924                utf16_range_to_replace: range_to_replace,
23925                text: text.into(),
23926            });
23927
23928            if let Some(new_selected_ranges) = new_selected_ranges {
23929                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23930                    selections.select_ranges(new_selected_ranges)
23931                });
23932                this.backspace(&Default::default(), window, cx);
23933            }
23934
23935            this.handle_input(text, window, cx);
23936        });
23937
23938        if let Some(transaction) = self.ime_transaction {
23939            self.buffer.update(cx, |buffer, cx| {
23940                buffer.group_until_transaction(transaction, cx);
23941            });
23942        }
23943
23944        self.unmark_text(window, cx);
23945    }
23946
23947    fn replace_and_mark_text_in_range(
23948        &mut self,
23949        range_utf16: Option<Range<usize>>,
23950        text: &str,
23951        new_selected_range_utf16: Option<Range<usize>>,
23952        window: &mut Window,
23953        cx: &mut Context<Self>,
23954    ) {
23955        if !self.input_enabled {
23956            return;
23957        }
23958
23959        let transaction = self.transact(window, cx, |this, window, cx| {
23960            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23961                let snapshot = this.buffer.read(cx).read(cx);
23962                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23963                    for marked_range in &mut marked_ranges {
23964                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23965                        marked_range.start.0 += relative_range_utf16.start;
23966                        marked_range.start =
23967                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23968                        marked_range.end =
23969                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23970                    }
23971                }
23972                Some(marked_ranges)
23973            } else if let Some(range_utf16) = range_utf16 {
23974                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23975                Some(this.selection_replacement_ranges(range_utf16, cx))
23976            } else {
23977                None
23978            };
23979
23980            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23981                let newest_selection_id = this.selections.newest_anchor().id;
23982                this.selections
23983                    .all::<OffsetUtf16>(cx)
23984                    .iter()
23985                    .zip(ranges_to_replace.iter())
23986                    .find_map(|(selection, range)| {
23987                        if selection.id == newest_selection_id {
23988                            Some(
23989                                (range.start.0 as isize - selection.head().0 as isize)
23990                                    ..(range.end.0 as isize - selection.head().0 as isize),
23991                            )
23992                        } else {
23993                            None
23994                        }
23995                    })
23996            });
23997
23998            cx.emit(EditorEvent::InputHandled {
23999                utf16_range_to_replace: range_to_replace,
24000                text: text.into(),
24001            });
24002
24003            if let Some(ranges) = ranges_to_replace {
24004                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24005                    s.select_ranges(ranges)
24006                });
24007            }
24008
24009            let marked_ranges = {
24010                let snapshot = this.buffer.read(cx).read(cx);
24011                this.selections
24012                    .disjoint_anchors_arc()
24013                    .iter()
24014                    .map(|selection| {
24015                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24016                    })
24017                    .collect::<Vec<_>>()
24018            };
24019
24020            if text.is_empty() {
24021                this.unmark_text(window, cx);
24022            } else {
24023                this.highlight_text::<InputComposition>(
24024                    marked_ranges.clone(),
24025                    HighlightStyle {
24026                        underline: Some(UnderlineStyle {
24027                            thickness: px(1.),
24028                            color: None,
24029                            wavy: false,
24030                        }),
24031                        ..Default::default()
24032                    },
24033                    cx,
24034                );
24035            }
24036
24037            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24038            let use_autoclose = this.use_autoclose;
24039            let use_auto_surround = this.use_auto_surround;
24040            this.set_use_autoclose(false);
24041            this.set_use_auto_surround(false);
24042            this.handle_input(text, window, cx);
24043            this.set_use_autoclose(use_autoclose);
24044            this.set_use_auto_surround(use_auto_surround);
24045
24046            if let Some(new_selected_range) = new_selected_range_utf16 {
24047                let snapshot = this.buffer.read(cx).read(cx);
24048                let new_selected_ranges = marked_ranges
24049                    .into_iter()
24050                    .map(|marked_range| {
24051                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24052                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24053                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24054                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24055                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24056                    })
24057                    .collect::<Vec<_>>();
24058
24059                drop(snapshot);
24060                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24061                    selections.select_ranges(new_selected_ranges)
24062                });
24063            }
24064        });
24065
24066        self.ime_transaction = self.ime_transaction.or(transaction);
24067        if let Some(transaction) = self.ime_transaction {
24068            self.buffer.update(cx, |buffer, cx| {
24069                buffer.group_until_transaction(transaction, cx);
24070            });
24071        }
24072
24073        if self.text_highlights::<InputComposition>(cx).is_none() {
24074            self.ime_transaction.take();
24075        }
24076    }
24077
24078    fn bounds_for_range(
24079        &mut self,
24080        range_utf16: Range<usize>,
24081        element_bounds: gpui::Bounds<Pixels>,
24082        window: &mut Window,
24083        cx: &mut Context<Self>,
24084    ) -> Option<gpui::Bounds<Pixels>> {
24085        let text_layout_details = self.text_layout_details(window);
24086        let CharacterDimensions {
24087            em_width,
24088            em_advance,
24089            line_height,
24090        } = self.character_dimensions(window);
24091
24092        let snapshot = self.snapshot(window, cx);
24093        let scroll_position = snapshot.scroll_position();
24094        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24095
24096        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24097        let x = Pixels::from(
24098            ScrollOffset::from(
24099                snapshot.x_for_display_point(start, &text_layout_details)
24100                    + self.gutter_dimensions.full_width(),
24101            ) - scroll_left,
24102        );
24103        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24104
24105        Some(Bounds {
24106            origin: element_bounds.origin + point(x, y),
24107            size: size(em_width, line_height),
24108        })
24109    }
24110
24111    fn character_index_for_point(
24112        &mut self,
24113        point: gpui::Point<Pixels>,
24114        _window: &mut Window,
24115        _cx: &mut Context<Self>,
24116    ) -> Option<usize> {
24117        let position_map = self.last_position_map.as_ref()?;
24118        if !position_map.text_hitbox.contains(&point) {
24119            return None;
24120        }
24121        let display_point = position_map.point_for_position(point).previous_valid;
24122        let anchor = position_map
24123            .snapshot
24124            .display_point_to_anchor(display_point, Bias::Left);
24125        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24126        Some(utf16_offset.0)
24127    }
24128}
24129
24130trait SelectionExt {
24131    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24132    fn spanned_rows(
24133        &self,
24134        include_end_if_at_line_start: bool,
24135        map: &DisplaySnapshot,
24136    ) -> Range<MultiBufferRow>;
24137}
24138
24139impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24140    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24141        let start = self
24142            .start
24143            .to_point(map.buffer_snapshot())
24144            .to_display_point(map);
24145        let end = self
24146            .end
24147            .to_point(map.buffer_snapshot())
24148            .to_display_point(map);
24149        if self.reversed {
24150            end..start
24151        } else {
24152            start..end
24153        }
24154    }
24155
24156    fn spanned_rows(
24157        &self,
24158        include_end_if_at_line_start: bool,
24159        map: &DisplaySnapshot,
24160    ) -> Range<MultiBufferRow> {
24161        let start = self.start.to_point(map.buffer_snapshot());
24162        let mut end = self.end.to_point(map.buffer_snapshot());
24163        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24164            end.row -= 1;
24165        }
24166
24167        let buffer_start = map.prev_line_boundary(start).0;
24168        let buffer_end = map.next_line_boundary(end).0;
24169        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24170    }
24171}
24172
24173impl<T: InvalidationRegion> InvalidationStack<T> {
24174    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24175    where
24176        S: Clone + ToOffset,
24177    {
24178        while let Some(region) = self.last() {
24179            let all_selections_inside_invalidation_ranges =
24180                if selections.len() == region.ranges().len() {
24181                    selections
24182                        .iter()
24183                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24184                        .all(|(selection, invalidation_range)| {
24185                            let head = selection.head().to_offset(buffer);
24186                            invalidation_range.start <= head && invalidation_range.end >= head
24187                        })
24188                } else {
24189                    false
24190                };
24191
24192            if all_selections_inside_invalidation_ranges {
24193                break;
24194            } else {
24195                self.pop();
24196            }
24197        }
24198    }
24199}
24200
24201impl<T> Default for InvalidationStack<T> {
24202    fn default() -> Self {
24203        Self(Default::default())
24204    }
24205}
24206
24207impl<T> Deref for InvalidationStack<T> {
24208    type Target = Vec<T>;
24209
24210    fn deref(&self) -> &Self::Target {
24211        &self.0
24212    }
24213}
24214
24215impl<T> DerefMut for InvalidationStack<T> {
24216    fn deref_mut(&mut self) -> &mut Self::Target {
24217        &mut self.0
24218    }
24219}
24220
24221impl InvalidationRegion for SnippetState {
24222    fn ranges(&self) -> &[Range<Anchor>] {
24223        &self.ranges[self.active_index]
24224    }
24225}
24226
24227fn edit_prediction_edit_text(
24228    current_snapshot: &BufferSnapshot,
24229    edits: &[(Range<Anchor>, String)],
24230    edit_preview: &EditPreview,
24231    include_deletions: bool,
24232    cx: &App,
24233) -> HighlightedText {
24234    let edits = edits
24235        .iter()
24236        .map(|(anchor, text)| {
24237            (
24238                anchor.start.text_anchor..anchor.end.text_anchor,
24239                text.clone(),
24240            )
24241        })
24242        .collect::<Vec<_>>();
24243
24244    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24245}
24246
24247fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24248    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24249    // Just show the raw edit text with basic styling
24250    let mut text = String::new();
24251    let mut highlights = Vec::new();
24252
24253    let insertion_highlight_style = HighlightStyle {
24254        color: Some(cx.theme().colors().text),
24255        ..Default::default()
24256    };
24257
24258    for (_, edit_text) in edits {
24259        let start_offset = text.len();
24260        text.push_str(edit_text);
24261        let end_offset = text.len();
24262
24263        if start_offset < end_offset {
24264            highlights.push((start_offset..end_offset, insertion_highlight_style));
24265        }
24266    }
24267
24268    HighlightedText {
24269        text: text.into(),
24270        highlights,
24271    }
24272}
24273
24274pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24275    match severity {
24276        lsp::DiagnosticSeverity::ERROR => colors.error,
24277        lsp::DiagnosticSeverity::WARNING => colors.warning,
24278        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24279        lsp::DiagnosticSeverity::HINT => colors.info,
24280        _ => colors.ignored,
24281    }
24282}
24283
24284pub fn styled_runs_for_code_label<'a>(
24285    label: &'a CodeLabel,
24286    syntax_theme: &'a theme::SyntaxTheme,
24287) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24288    let fade_out = HighlightStyle {
24289        fade_out: Some(0.35),
24290        ..Default::default()
24291    };
24292
24293    let mut prev_end = label.filter_range.end;
24294    label
24295        .runs
24296        .iter()
24297        .enumerate()
24298        .flat_map(move |(ix, (range, highlight_id))| {
24299            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24300                style
24301            } else {
24302                return Default::default();
24303            };
24304            let muted_style = style.highlight(fade_out);
24305
24306            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24307            if range.start >= label.filter_range.end {
24308                if range.start > prev_end {
24309                    runs.push((prev_end..range.start, fade_out));
24310                }
24311                runs.push((range.clone(), muted_style));
24312            } else if range.end <= label.filter_range.end {
24313                runs.push((range.clone(), style));
24314            } else {
24315                runs.push((range.start..label.filter_range.end, style));
24316                runs.push((label.filter_range.end..range.end, muted_style));
24317            }
24318            prev_end = cmp::max(prev_end, range.end);
24319
24320            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24321                runs.push((prev_end..label.text.len(), fade_out));
24322            }
24323
24324            runs
24325        })
24326}
24327
24328pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24329    let mut prev_index = 0;
24330    let mut prev_codepoint: Option<char> = None;
24331    text.char_indices()
24332        .chain([(text.len(), '\0')])
24333        .filter_map(move |(index, codepoint)| {
24334            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24335            let is_boundary = index == text.len()
24336                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24337                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24338            if is_boundary {
24339                let chunk = &text[prev_index..index];
24340                prev_index = index;
24341                Some(chunk)
24342            } else {
24343                None
24344            }
24345        })
24346}
24347
24348pub trait RangeToAnchorExt: Sized {
24349    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24350
24351    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24352        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24353        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24354    }
24355}
24356
24357impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24358    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24359        let start_offset = self.start.to_offset(snapshot);
24360        let end_offset = self.end.to_offset(snapshot);
24361        if start_offset == end_offset {
24362            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24363        } else {
24364            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24365        }
24366    }
24367}
24368
24369pub trait RowExt {
24370    fn as_f64(&self) -> f64;
24371
24372    fn next_row(&self) -> Self;
24373
24374    fn previous_row(&self) -> Self;
24375
24376    fn minus(&self, other: Self) -> u32;
24377}
24378
24379impl RowExt for DisplayRow {
24380    fn as_f64(&self) -> f64 {
24381        self.0 as _
24382    }
24383
24384    fn next_row(&self) -> Self {
24385        Self(self.0 + 1)
24386    }
24387
24388    fn previous_row(&self) -> Self {
24389        Self(self.0.saturating_sub(1))
24390    }
24391
24392    fn minus(&self, other: Self) -> u32 {
24393        self.0 - other.0
24394    }
24395}
24396
24397impl RowExt for MultiBufferRow {
24398    fn as_f64(&self) -> f64 {
24399        self.0 as _
24400    }
24401
24402    fn next_row(&self) -> Self {
24403        Self(self.0 + 1)
24404    }
24405
24406    fn previous_row(&self) -> Self {
24407        Self(self.0.saturating_sub(1))
24408    }
24409
24410    fn minus(&self, other: Self) -> u32 {
24411        self.0 - other.0
24412    }
24413}
24414
24415trait RowRangeExt {
24416    type Row;
24417
24418    fn len(&self) -> usize;
24419
24420    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24421}
24422
24423impl RowRangeExt for Range<MultiBufferRow> {
24424    type Row = MultiBufferRow;
24425
24426    fn len(&self) -> usize {
24427        (self.end.0 - self.start.0) as usize
24428    }
24429
24430    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24431        (self.start.0..self.end.0).map(MultiBufferRow)
24432    }
24433}
24434
24435impl RowRangeExt for Range<DisplayRow> {
24436    type Row = DisplayRow;
24437
24438    fn len(&self) -> usize {
24439        (self.end.0 - self.start.0) as usize
24440    }
24441
24442    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24443        (self.start.0..self.end.0).map(DisplayRow)
24444    }
24445}
24446
24447/// If select range has more than one line, we
24448/// just point the cursor to range.start.
24449fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24450    if range.start.row == range.end.row {
24451        range
24452    } else {
24453        range.start..range.start
24454    }
24455}
24456pub struct KillRing(ClipboardItem);
24457impl Global for KillRing {}
24458
24459const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24460
24461enum BreakpointPromptEditAction {
24462    Log,
24463    Condition,
24464    HitCondition,
24465}
24466
24467struct BreakpointPromptEditor {
24468    pub(crate) prompt: Entity<Editor>,
24469    editor: WeakEntity<Editor>,
24470    breakpoint_anchor: Anchor,
24471    breakpoint: Breakpoint,
24472    edit_action: BreakpointPromptEditAction,
24473    block_ids: HashSet<CustomBlockId>,
24474    editor_margins: Arc<Mutex<EditorMargins>>,
24475    _subscriptions: Vec<Subscription>,
24476}
24477
24478impl BreakpointPromptEditor {
24479    const MAX_LINES: u8 = 4;
24480
24481    fn new(
24482        editor: WeakEntity<Editor>,
24483        breakpoint_anchor: Anchor,
24484        breakpoint: Breakpoint,
24485        edit_action: BreakpointPromptEditAction,
24486        window: &mut Window,
24487        cx: &mut Context<Self>,
24488    ) -> Self {
24489        let base_text = match edit_action {
24490            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24491            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24492            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24493        }
24494        .map(|msg| msg.to_string())
24495        .unwrap_or_default();
24496
24497        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24498        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24499
24500        let prompt = cx.new(|cx| {
24501            let mut prompt = Editor::new(
24502                EditorMode::AutoHeight {
24503                    min_lines: 1,
24504                    max_lines: Some(Self::MAX_LINES as usize),
24505                },
24506                buffer,
24507                None,
24508                window,
24509                cx,
24510            );
24511            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24512            prompt.set_show_cursor_when_unfocused(false, cx);
24513            prompt.set_placeholder_text(
24514                match edit_action {
24515                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24516                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24517                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24518                },
24519                window,
24520                cx,
24521            );
24522
24523            prompt
24524        });
24525
24526        Self {
24527            prompt,
24528            editor,
24529            breakpoint_anchor,
24530            breakpoint,
24531            edit_action,
24532            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24533            block_ids: Default::default(),
24534            _subscriptions: vec![],
24535        }
24536    }
24537
24538    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24539        self.block_ids.extend(block_ids)
24540    }
24541
24542    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24543        if let Some(editor) = self.editor.upgrade() {
24544            let message = self
24545                .prompt
24546                .read(cx)
24547                .buffer
24548                .read(cx)
24549                .as_singleton()
24550                .expect("A multi buffer in breakpoint prompt isn't possible")
24551                .read(cx)
24552                .as_rope()
24553                .to_string();
24554
24555            editor.update(cx, |editor, cx| {
24556                editor.edit_breakpoint_at_anchor(
24557                    self.breakpoint_anchor,
24558                    self.breakpoint.clone(),
24559                    match self.edit_action {
24560                        BreakpointPromptEditAction::Log => {
24561                            BreakpointEditAction::EditLogMessage(message.into())
24562                        }
24563                        BreakpointPromptEditAction::Condition => {
24564                            BreakpointEditAction::EditCondition(message.into())
24565                        }
24566                        BreakpointPromptEditAction::HitCondition => {
24567                            BreakpointEditAction::EditHitCondition(message.into())
24568                        }
24569                    },
24570                    cx,
24571                );
24572
24573                editor.remove_blocks(self.block_ids.clone(), None, cx);
24574                cx.focus_self(window);
24575            });
24576        }
24577    }
24578
24579    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24580        self.editor
24581            .update(cx, |editor, cx| {
24582                editor.remove_blocks(self.block_ids.clone(), None, cx);
24583                window.focus(&editor.focus_handle);
24584            })
24585            .log_err();
24586    }
24587
24588    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24589        let settings = ThemeSettings::get_global(cx);
24590        let text_style = TextStyle {
24591            color: if self.prompt.read(cx).read_only(cx) {
24592                cx.theme().colors().text_disabled
24593            } else {
24594                cx.theme().colors().text
24595            },
24596            font_family: settings.buffer_font.family.clone(),
24597            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24598            font_size: settings.buffer_font_size(cx).into(),
24599            font_weight: settings.buffer_font.weight,
24600            line_height: relative(settings.buffer_line_height.value()),
24601            ..Default::default()
24602        };
24603        EditorElement::new(
24604            &self.prompt,
24605            EditorStyle {
24606                background: cx.theme().colors().editor_background,
24607                local_player: cx.theme().players().local(),
24608                text: text_style,
24609                ..Default::default()
24610            },
24611        )
24612    }
24613}
24614
24615impl Render for BreakpointPromptEditor {
24616    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24617        let editor_margins = *self.editor_margins.lock();
24618        let gutter_dimensions = editor_margins.gutter;
24619        h_flex()
24620            .key_context("Editor")
24621            .bg(cx.theme().colors().editor_background)
24622            .border_y_1()
24623            .border_color(cx.theme().status().info_border)
24624            .size_full()
24625            .py(window.line_height() / 2.5)
24626            .on_action(cx.listener(Self::confirm))
24627            .on_action(cx.listener(Self::cancel))
24628            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24629            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24630    }
24631}
24632
24633impl Focusable for BreakpointPromptEditor {
24634    fn focus_handle(&self, cx: &App) -> FocusHandle {
24635        self.prompt.focus_handle(cx)
24636    }
24637}
24638
24639fn all_edits_insertions_or_deletions(
24640    edits: &Vec<(Range<Anchor>, String)>,
24641    snapshot: &MultiBufferSnapshot,
24642) -> bool {
24643    let mut all_insertions = true;
24644    let mut all_deletions = true;
24645
24646    for (range, new_text) in edits.iter() {
24647        let range_is_empty = range.to_offset(snapshot).is_empty();
24648        let text_is_empty = new_text.is_empty();
24649
24650        if range_is_empty != text_is_empty {
24651            if range_is_empty {
24652                all_deletions = false;
24653            } else {
24654                all_insertions = false;
24655            }
24656        } else {
24657            return false;
24658        }
24659
24660        if !all_insertions && !all_deletions {
24661            return false;
24662        }
24663    }
24664    all_insertions || all_deletions
24665}
24666
24667struct MissingEditPredictionKeybindingTooltip;
24668
24669impl Render for MissingEditPredictionKeybindingTooltip {
24670    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24671        ui::tooltip_container(cx, |container, cx| {
24672            container
24673                .flex_shrink_0()
24674                .max_w_80()
24675                .min_h(rems_from_px(124.))
24676                .justify_between()
24677                .child(
24678                    v_flex()
24679                        .flex_1()
24680                        .text_ui_sm(cx)
24681                        .child(Label::new("Conflict with Accept Keybinding"))
24682                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24683                )
24684                .child(
24685                    h_flex()
24686                        .pb_1()
24687                        .gap_1()
24688                        .items_end()
24689                        .w_full()
24690                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24691                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24692                        }))
24693                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24694                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24695                        })),
24696                )
24697        })
24698    }
24699}
24700
24701#[derive(Debug, Clone, Copy, PartialEq)]
24702pub struct LineHighlight {
24703    pub background: Background,
24704    pub border: Option<gpui::Hsla>,
24705    pub include_gutter: bool,
24706    pub type_id: Option<TypeId>,
24707}
24708
24709struct LineManipulationResult {
24710    pub new_text: String,
24711    pub line_count_before: usize,
24712    pub line_count_after: usize,
24713}
24714
24715fn render_diff_hunk_controls(
24716    row: u32,
24717    status: &DiffHunkStatus,
24718    hunk_range: Range<Anchor>,
24719    is_created_file: bool,
24720    line_height: Pixels,
24721    editor: &Entity<Editor>,
24722    _window: &mut Window,
24723    cx: &mut App,
24724) -> AnyElement {
24725    h_flex()
24726        .h(line_height)
24727        .mr_1()
24728        .gap_1()
24729        .px_0p5()
24730        .pb_1()
24731        .border_x_1()
24732        .border_b_1()
24733        .border_color(cx.theme().colors().border_variant)
24734        .rounded_b_lg()
24735        .bg(cx.theme().colors().editor_background)
24736        .gap_1()
24737        .block_mouse_except_scroll()
24738        .shadow_md()
24739        .child(if status.has_secondary_hunk() {
24740            Button::new(("stage", row as u64), "Stage")
24741                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24742                .tooltip({
24743                    let focus_handle = editor.focus_handle(cx);
24744                    move |window, cx| {
24745                        Tooltip::for_action_in(
24746                            "Stage Hunk",
24747                            &::git::ToggleStaged,
24748                            &focus_handle,
24749                            window,
24750                            cx,
24751                        )
24752                    }
24753                })
24754                .on_click({
24755                    let editor = editor.clone();
24756                    move |_event, _window, cx| {
24757                        editor.update(cx, |editor, cx| {
24758                            editor.stage_or_unstage_diff_hunks(
24759                                true,
24760                                vec![hunk_range.start..hunk_range.start],
24761                                cx,
24762                            );
24763                        });
24764                    }
24765                })
24766        } else {
24767            Button::new(("unstage", row as u64), "Unstage")
24768                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24769                .tooltip({
24770                    let focus_handle = editor.focus_handle(cx);
24771                    move |window, cx| {
24772                        Tooltip::for_action_in(
24773                            "Unstage Hunk",
24774                            &::git::ToggleStaged,
24775                            &focus_handle,
24776                            window,
24777                            cx,
24778                        )
24779                    }
24780                })
24781                .on_click({
24782                    let editor = editor.clone();
24783                    move |_event, _window, cx| {
24784                        editor.update(cx, |editor, cx| {
24785                            editor.stage_or_unstage_diff_hunks(
24786                                false,
24787                                vec![hunk_range.start..hunk_range.start],
24788                                cx,
24789                            );
24790                        });
24791                    }
24792                })
24793        })
24794        .child(
24795            Button::new(("restore", row as u64), "Restore")
24796                .tooltip({
24797                    let focus_handle = editor.focus_handle(cx);
24798                    move |window, cx| {
24799                        Tooltip::for_action_in(
24800                            "Restore Hunk",
24801                            &::git::Restore,
24802                            &focus_handle,
24803                            window,
24804                            cx,
24805                        )
24806                    }
24807                })
24808                .on_click({
24809                    let editor = editor.clone();
24810                    move |_event, window, cx| {
24811                        editor.update(cx, |editor, cx| {
24812                            let snapshot = editor.snapshot(window, cx);
24813                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24814                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24815                        });
24816                    }
24817                })
24818                .disabled(is_created_file),
24819        )
24820        .when(
24821            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24822            |el| {
24823                el.child(
24824                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24825                        .shape(IconButtonShape::Square)
24826                        .icon_size(IconSize::Small)
24827                        // .disabled(!has_multiple_hunks)
24828                        .tooltip({
24829                            let focus_handle = editor.focus_handle(cx);
24830                            move |window, cx| {
24831                                Tooltip::for_action_in(
24832                                    "Next Hunk",
24833                                    &GoToHunk,
24834                                    &focus_handle,
24835                                    window,
24836                                    cx,
24837                                )
24838                            }
24839                        })
24840                        .on_click({
24841                            let editor = editor.clone();
24842                            move |_event, window, cx| {
24843                                editor.update(cx, |editor, cx| {
24844                                    let snapshot = editor.snapshot(window, cx);
24845                                    let position =
24846                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24847                                    editor.go_to_hunk_before_or_after_position(
24848                                        &snapshot,
24849                                        position,
24850                                        Direction::Next,
24851                                        window,
24852                                        cx,
24853                                    );
24854                                    editor.expand_selected_diff_hunks(cx);
24855                                });
24856                            }
24857                        }),
24858                )
24859                .child(
24860                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24861                        .shape(IconButtonShape::Square)
24862                        .icon_size(IconSize::Small)
24863                        // .disabled(!has_multiple_hunks)
24864                        .tooltip({
24865                            let focus_handle = editor.focus_handle(cx);
24866                            move |window, cx| {
24867                                Tooltip::for_action_in(
24868                                    "Previous Hunk",
24869                                    &GoToPreviousHunk,
24870                                    &focus_handle,
24871                                    window,
24872                                    cx,
24873                                )
24874                            }
24875                        })
24876                        .on_click({
24877                            let editor = editor.clone();
24878                            move |_event, window, cx| {
24879                                editor.update(cx, |editor, cx| {
24880                                    let snapshot = editor.snapshot(window, cx);
24881                                    let point =
24882                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24883                                    editor.go_to_hunk_before_or_after_position(
24884                                        &snapshot,
24885                                        point,
24886                                        Direction::Prev,
24887                                        window,
24888                                        cx,
24889                                    );
24890                                    editor.expand_selected_diff_hunks(cx);
24891                                });
24892                            }
24893                        }),
24894                )
24895            },
24896        )
24897        .into_any_element()
24898}
24899
24900pub fn multibuffer_context_lines(cx: &App) -> u32 {
24901    EditorSettings::try_get(cx)
24902        .map(|settings| settings.excerpt_context_lines)
24903        .unwrap_or(2)
24904        .min(32)
24905}