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    post_scroll_update: Task<()>,
 1194    refresh_colors_task: Task<()>,
 1195    folding_newlines: Task<()>,
 1196    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1197}
 1198
 1199#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1200enum NextScrollCursorCenterTopBottom {
 1201    #[default]
 1202    Center,
 1203    Top,
 1204    Bottom,
 1205}
 1206
 1207impl NextScrollCursorCenterTopBottom {
 1208    fn next(&self) -> Self {
 1209        match self {
 1210            Self::Center => Self::Top,
 1211            Self::Top => Self::Bottom,
 1212            Self::Bottom => Self::Center,
 1213        }
 1214    }
 1215}
 1216
 1217#[derive(Clone)]
 1218pub struct EditorSnapshot {
 1219    pub mode: EditorMode,
 1220    show_gutter: bool,
 1221    show_line_numbers: Option<bool>,
 1222    show_git_diff_gutter: Option<bool>,
 1223    show_code_actions: Option<bool>,
 1224    show_runnables: Option<bool>,
 1225    show_breakpoints: Option<bool>,
 1226    git_blame_gutter_max_author_length: Option<usize>,
 1227    pub display_snapshot: DisplaySnapshot,
 1228    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1229    is_focused: bool,
 1230    scroll_anchor: ScrollAnchor,
 1231    ongoing_scroll: OngoingScroll,
 1232    current_line_highlight: CurrentLineHighlight,
 1233    gutter_hovered: bool,
 1234}
 1235
 1236#[derive(Default, Debug, Clone, Copy)]
 1237pub struct GutterDimensions {
 1238    pub left_padding: Pixels,
 1239    pub right_padding: Pixels,
 1240    pub width: Pixels,
 1241    pub margin: Pixels,
 1242    pub git_blame_entries_width: Option<Pixels>,
 1243}
 1244
 1245impl GutterDimensions {
 1246    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1247        Self {
 1248            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1249            ..Default::default()
 1250        }
 1251    }
 1252
 1253    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1254        -cx.text_system().descent(font_id, font_size)
 1255    }
 1256    /// The full width of the space taken up by the gutter.
 1257    pub fn full_width(&self) -> Pixels {
 1258        self.margin + self.width
 1259    }
 1260
 1261    /// The width of the space reserved for the fold indicators,
 1262    /// use alongside 'justify_end' and `gutter_width` to
 1263    /// right align content with the line numbers
 1264    pub fn fold_area_width(&self) -> Pixels {
 1265        self.margin + self.right_padding
 1266    }
 1267}
 1268
 1269struct CharacterDimensions {
 1270    em_width: Pixels,
 1271    em_advance: Pixels,
 1272    line_height: Pixels,
 1273}
 1274
 1275#[derive(Debug)]
 1276pub struct RemoteSelection {
 1277    pub replica_id: ReplicaId,
 1278    pub selection: Selection<Anchor>,
 1279    pub cursor_shape: CursorShape,
 1280    pub collaborator_id: CollaboratorId,
 1281    pub line_mode: bool,
 1282    pub user_name: Option<SharedString>,
 1283    pub color: PlayerColor,
 1284}
 1285
 1286#[derive(Clone, Debug)]
 1287struct SelectionHistoryEntry {
 1288    selections: Arc<[Selection<Anchor>]>,
 1289    select_next_state: Option<SelectNextState>,
 1290    select_prev_state: Option<SelectNextState>,
 1291    add_selections_state: Option<AddSelectionsState>,
 1292}
 1293
 1294#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1295enum SelectionHistoryMode {
 1296    Normal,
 1297    Undoing,
 1298    Redoing,
 1299    Skipping,
 1300}
 1301
 1302#[derive(Clone, PartialEq, Eq, Hash)]
 1303struct HoveredCursor {
 1304    replica_id: u16,
 1305    selection_id: usize,
 1306}
 1307
 1308impl Default for SelectionHistoryMode {
 1309    fn default() -> Self {
 1310        Self::Normal
 1311    }
 1312}
 1313
 1314#[derive(Debug)]
 1315/// SelectionEffects controls the side-effects of updating the selection.
 1316///
 1317/// The default behaviour does "what you mostly want":
 1318/// - it pushes to the nav history if the cursor moved by >10 lines
 1319/// - it re-triggers completion requests
 1320/// - it scrolls to fit
 1321///
 1322/// You might want to modify these behaviours. For example when doing a "jump"
 1323/// like go to definition, we always want to add to nav history; but when scrolling
 1324/// in vim mode we never do.
 1325///
 1326/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1327/// move.
 1328#[derive(Clone)]
 1329pub struct SelectionEffects {
 1330    nav_history: Option<bool>,
 1331    completions: bool,
 1332    scroll: Option<Autoscroll>,
 1333}
 1334
 1335impl Default for SelectionEffects {
 1336    fn default() -> Self {
 1337        Self {
 1338            nav_history: None,
 1339            completions: true,
 1340            scroll: Some(Autoscroll::fit()),
 1341        }
 1342    }
 1343}
 1344impl SelectionEffects {
 1345    pub fn scroll(scroll: Autoscroll) -> Self {
 1346        Self {
 1347            scroll: Some(scroll),
 1348            ..Default::default()
 1349        }
 1350    }
 1351
 1352    pub fn no_scroll() -> Self {
 1353        Self {
 1354            scroll: None,
 1355            ..Default::default()
 1356        }
 1357    }
 1358
 1359    pub fn completions(self, completions: bool) -> Self {
 1360        Self {
 1361            completions,
 1362            ..self
 1363        }
 1364    }
 1365
 1366    pub fn nav_history(self, nav_history: bool) -> Self {
 1367        Self {
 1368            nav_history: Some(nav_history),
 1369            ..self
 1370        }
 1371    }
 1372}
 1373
 1374struct DeferredSelectionEffectsState {
 1375    changed: bool,
 1376    effects: SelectionEffects,
 1377    old_cursor_position: Anchor,
 1378    history_entry: SelectionHistoryEntry,
 1379}
 1380
 1381#[derive(Default)]
 1382struct SelectionHistory {
 1383    #[allow(clippy::type_complexity)]
 1384    selections_by_transaction:
 1385        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1386    mode: SelectionHistoryMode,
 1387    undo_stack: VecDeque<SelectionHistoryEntry>,
 1388    redo_stack: VecDeque<SelectionHistoryEntry>,
 1389}
 1390
 1391impl SelectionHistory {
 1392    #[track_caller]
 1393    fn insert_transaction(
 1394        &mut self,
 1395        transaction_id: TransactionId,
 1396        selections: Arc<[Selection<Anchor>]>,
 1397    ) {
 1398        if selections.is_empty() {
 1399            log::error!(
 1400                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1401                std::panic::Location::caller()
 1402            );
 1403            return;
 1404        }
 1405        self.selections_by_transaction
 1406            .insert(transaction_id, (selections, None));
 1407    }
 1408
 1409    #[allow(clippy::type_complexity)]
 1410    fn transaction(
 1411        &self,
 1412        transaction_id: TransactionId,
 1413    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1414        self.selections_by_transaction.get(&transaction_id)
 1415    }
 1416
 1417    #[allow(clippy::type_complexity)]
 1418    fn transaction_mut(
 1419        &mut self,
 1420        transaction_id: TransactionId,
 1421    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1422        self.selections_by_transaction.get_mut(&transaction_id)
 1423    }
 1424
 1425    fn push(&mut self, entry: SelectionHistoryEntry) {
 1426        if !entry.selections.is_empty() {
 1427            match self.mode {
 1428                SelectionHistoryMode::Normal => {
 1429                    self.push_undo(entry);
 1430                    self.redo_stack.clear();
 1431                }
 1432                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1433                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1434                SelectionHistoryMode::Skipping => {}
 1435            }
 1436        }
 1437    }
 1438
 1439    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1440        if self
 1441            .undo_stack
 1442            .back()
 1443            .is_none_or(|e| e.selections != entry.selections)
 1444        {
 1445            self.undo_stack.push_back(entry);
 1446            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1447                self.undo_stack.pop_front();
 1448            }
 1449        }
 1450    }
 1451
 1452    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1453        if self
 1454            .redo_stack
 1455            .back()
 1456            .is_none_or(|e| e.selections != entry.selections)
 1457        {
 1458            self.redo_stack.push_back(entry);
 1459            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1460                self.redo_stack.pop_front();
 1461            }
 1462        }
 1463    }
 1464}
 1465
 1466#[derive(Clone, Copy)]
 1467pub struct RowHighlightOptions {
 1468    pub autoscroll: bool,
 1469    pub include_gutter: bool,
 1470}
 1471
 1472impl Default for RowHighlightOptions {
 1473    fn default() -> Self {
 1474        Self {
 1475            autoscroll: Default::default(),
 1476            include_gutter: true,
 1477        }
 1478    }
 1479}
 1480
 1481struct RowHighlight {
 1482    index: usize,
 1483    range: Range<Anchor>,
 1484    color: Hsla,
 1485    options: RowHighlightOptions,
 1486    type_id: TypeId,
 1487}
 1488
 1489#[derive(Clone, Debug)]
 1490struct AddSelectionsState {
 1491    groups: Vec<AddSelectionsGroup>,
 1492}
 1493
 1494#[derive(Clone, Debug)]
 1495struct AddSelectionsGroup {
 1496    above: bool,
 1497    stack: Vec<usize>,
 1498}
 1499
 1500#[derive(Clone)]
 1501struct SelectNextState {
 1502    query: AhoCorasick,
 1503    wordwise: bool,
 1504    done: bool,
 1505}
 1506
 1507impl std::fmt::Debug for SelectNextState {
 1508    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1509        f.debug_struct(std::any::type_name::<Self>())
 1510            .field("wordwise", &self.wordwise)
 1511            .field("done", &self.done)
 1512            .finish()
 1513    }
 1514}
 1515
 1516#[derive(Debug)]
 1517struct AutocloseRegion {
 1518    selection_id: usize,
 1519    range: Range<Anchor>,
 1520    pair: BracketPair,
 1521}
 1522
 1523#[derive(Debug)]
 1524struct SnippetState {
 1525    ranges: Vec<Vec<Range<Anchor>>>,
 1526    active_index: usize,
 1527    choices: Vec<Option<Vec<String>>>,
 1528}
 1529
 1530#[doc(hidden)]
 1531pub struct RenameState {
 1532    pub range: Range<Anchor>,
 1533    pub old_name: Arc<str>,
 1534    pub editor: Entity<Editor>,
 1535    block_id: CustomBlockId,
 1536}
 1537
 1538struct InvalidationStack<T>(Vec<T>);
 1539
 1540struct RegisteredEditPredictionProvider {
 1541    provider: Arc<dyn EditPredictionProviderHandle>,
 1542    _subscription: Subscription,
 1543}
 1544
 1545#[derive(Debug, PartialEq, Eq)]
 1546pub struct ActiveDiagnosticGroup {
 1547    pub active_range: Range<Anchor>,
 1548    pub active_message: String,
 1549    pub group_id: usize,
 1550    pub blocks: HashSet<CustomBlockId>,
 1551}
 1552
 1553#[derive(Debug, PartialEq, Eq)]
 1554
 1555pub(crate) enum ActiveDiagnostic {
 1556    None,
 1557    All,
 1558    Group(ActiveDiagnosticGroup),
 1559}
 1560
 1561#[derive(Serialize, Deserialize, Clone, Debug)]
 1562pub struct ClipboardSelection {
 1563    /// The number of bytes in this selection.
 1564    pub len: usize,
 1565    /// Whether this was a full-line selection.
 1566    pub is_entire_line: bool,
 1567    /// The indentation of the first line when this content was originally copied.
 1568    pub first_line_indent: u32,
 1569}
 1570
 1571// selections, scroll behavior, was newest selection reversed
 1572type SelectSyntaxNodeHistoryState = (
 1573    Box<[Selection<usize>]>,
 1574    SelectSyntaxNodeScrollBehavior,
 1575    bool,
 1576);
 1577
 1578#[derive(Default)]
 1579struct SelectSyntaxNodeHistory {
 1580    stack: Vec<SelectSyntaxNodeHistoryState>,
 1581    // disable temporarily to allow changing selections without losing the stack
 1582    pub disable_clearing: bool,
 1583}
 1584
 1585impl SelectSyntaxNodeHistory {
 1586    pub fn try_clear(&mut self) {
 1587        if !self.disable_clearing {
 1588            self.stack.clear();
 1589        }
 1590    }
 1591
 1592    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1593        self.stack.push(selection);
 1594    }
 1595
 1596    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1597        self.stack.pop()
 1598    }
 1599}
 1600
 1601enum SelectSyntaxNodeScrollBehavior {
 1602    CursorTop,
 1603    FitSelection,
 1604    CursorBottom,
 1605}
 1606
 1607#[derive(Debug)]
 1608pub(crate) struct NavigationData {
 1609    cursor_anchor: Anchor,
 1610    cursor_position: Point,
 1611    scroll_anchor: ScrollAnchor,
 1612    scroll_top_row: u32,
 1613}
 1614
 1615#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1616pub enum GotoDefinitionKind {
 1617    Symbol,
 1618    Declaration,
 1619    Type,
 1620    Implementation,
 1621}
 1622
 1623#[derive(Debug, Clone)]
 1624enum InlayHintRefreshReason {
 1625    ModifiersChanged(bool),
 1626    Toggle(bool),
 1627    SettingsChange(InlayHintSettings),
 1628    NewLinesShown,
 1629    BufferEdited(HashSet<Arc<Language>>),
 1630    RefreshRequested,
 1631    ExcerptsRemoved(Vec<ExcerptId>),
 1632}
 1633
 1634impl InlayHintRefreshReason {
 1635    fn description(&self) -> &'static str {
 1636        match self {
 1637            Self::ModifiersChanged(_) => "modifiers changed",
 1638            Self::Toggle(_) => "toggle",
 1639            Self::SettingsChange(_) => "settings change",
 1640            Self::NewLinesShown => "new lines shown",
 1641            Self::BufferEdited(_) => "buffer edited",
 1642            Self::RefreshRequested => "refresh requested",
 1643            Self::ExcerptsRemoved(_) => "excerpts removed",
 1644        }
 1645    }
 1646}
 1647
 1648pub enum FormatTarget {
 1649    Buffers(HashSet<Entity<Buffer>>),
 1650    Ranges(Vec<Range<MultiBufferPoint>>),
 1651}
 1652
 1653pub(crate) struct FocusedBlock {
 1654    id: BlockId,
 1655    focus_handle: WeakFocusHandle,
 1656}
 1657
 1658#[derive(Clone)]
 1659enum JumpData {
 1660    MultiBufferRow {
 1661        row: MultiBufferRow,
 1662        line_offset_from_top: u32,
 1663    },
 1664    MultiBufferPoint {
 1665        excerpt_id: ExcerptId,
 1666        position: Point,
 1667        anchor: text::Anchor,
 1668        line_offset_from_top: u32,
 1669    },
 1670}
 1671
 1672pub enum MultibufferSelectionMode {
 1673    First,
 1674    All,
 1675}
 1676
 1677#[derive(Clone, Copy, Debug, Default)]
 1678pub struct RewrapOptions {
 1679    pub override_language_settings: bool,
 1680    pub preserve_existing_whitespace: bool,
 1681}
 1682
 1683impl Editor {
 1684    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1688    }
 1689
 1690    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1691        let buffer = cx.new(|cx| Buffer::local("", cx));
 1692        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1693        Self::new(EditorMode::full(), buffer, None, window, cx)
 1694    }
 1695
 1696    pub fn auto_height(
 1697        min_lines: usize,
 1698        max_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: Some(max_lines),
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1717    /// The editor grows as tall as needed to fit its content.
 1718    pub fn auto_height_unbounded(
 1719        min_lines: usize,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| Buffer::local("", cx));
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(
 1726            EditorMode::AutoHeight {
 1727                min_lines,
 1728                max_lines: None,
 1729            },
 1730            buffer,
 1731            None,
 1732            window,
 1733            cx,
 1734        )
 1735    }
 1736
 1737    pub fn for_buffer(
 1738        buffer: Entity<Buffer>,
 1739        project: Option<Entity<Project>>,
 1740        window: &mut Window,
 1741        cx: &mut Context<Self>,
 1742    ) -> Self {
 1743        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1744        Self::new(EditorMode::full(), buffer, project, window, cx)
 1745    }
 1746
 1747    pub fn for_multibuffer(
 1748        buffer: Entity<MultiBuffer>,
 1749        project: Option<Entity<Project>>,
 1750        window: &mut Window,
 1751        cx: &mut Context<Self>,
 1752    ) -> Self {
 1753        Self::new(EditorMode::full(), buffer, project, window, cx)
 1754    }
 1755
 1756    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1757        let mut clone = Self::new(
 1758            self.mode.clone(),
 1759            self.buffer.clone(),
 1760            self.project.clone(),
 1761            window,
 1762            cx,
 1763        );
 1764        self.display_map.update(cx, |display_map, cx| {
 1765            let snapshot = display_map.snapshot(cx);
 1766            clone.display_map.update(cx, |display_map, cx| {
 1767                display_map.set_state(&snapshot, cx);
 1768            });
 1769        });
 1770        clone.folds_did_change(cx);
 1771        clone.selections.clone_state(&self.selections);
 1772        clone.scroll_manager.clone_state(&self.scroll_manager);
 1773        clone.searchable = self.searchable;
 1774        clone.read_only = self.read_only;
 1775        clone
 1776    }
 1777
 1778    pub fn new(
 1779        mode: EditorMode,
 1780        buffer: Entity<MultiBuffer>,
 1781        project: Option<Entity<Project>>,
 1782        window: &mut Window,
 1783        cx: &mut Context<Self>,
 1784    ) -> Self {
 1785        Editor::new_internal(mode, buffer, project, None, window, cx)
 1786    }
 1787
 1788    fn new_internal(
 1789        mode: EditorMode,
 1790        multi_buffer: Entity<MultiBuffer>,
 1791        project: Option<Entity<Project>>,
 1792        display_map: Option<Entity<DisplayMap>>,
 1793        window: &mut Window,
 1794        cx: &mut Context<Self>,
 1795    ) -> Self {
 1796        debug_assert!(
 1797            display_map.is_none() || mode.is_minimap(),
 1798            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1799        );
 1800
 1801        let full_mode = mode.is_full();
 1802        let is_minimap = mode.is_minimap();
 1803        let diagnostics_max_severity = if full_mode {
 1804            EditorSettings::get_global(cx)
 1805                .diagnostics_max_severity
 1806                .unwrap_or(DiagnosticSeverity::Hint)
 1807        } else {
 1808            DiagnosticSeverity::Off
 1809        };
 1810        let style = window.text_style();
 1811        let font_size = style.font_size.to_pixels(window.rem_size());
 1812        let editor = cx.entity().downgrade();
 1813        let fold_placeholder = FoldPlaceholder {
 1814            constrain_width: false,
 1815            render: Arc::new(move |fold_id, fold_range, cx| {
 1816                let editor = editor.clone();
 1817                div()
 1818                    .id(fold_id)
 1819                    .bg(cx.theme().colors().ghost_element_background)
 1820                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1821                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1822                    .rounded_xs()
 1823                    .size_full()
 1824                    .cursor_pointer()
 1825                    .child("")
 1826                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1827                    .on_click(move |_, _window, cx| {
 1828                        editor
 1829                            .update(cx, |editor, cx| {
 1830                                editor.unfold_ranges(
 1831                                    &[fold_range.start..fold_range.end],
 1832                                    true,
 1833                                    false,
 1834                                    cx,
 1835                                );
 1836                                cx.stop_propagation();
 1837                            })
 1838                            .ok();
 1839                    })
 1840                    .into_any()
 1841            }),
 1842            merge_adjacent: true,
 1843            ..FoldPlaceholder::default()
 1844        };
 1845        let display_map = display_map.unwrap_or_else(|| {
 1846            cx.new(|cx| {
 1847                DisplayMap::new(
 1848                    multi_buffer.clone(),
 1849                    style.font(),
 1850                    font_size,
 1851                    None,
 1852                    FILE_HEADER_HEIGHT,
 1853                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1854                    fold_placeholder,
 1855                    diagnostics_max_severity,
 1856                    cx,
 1857                )
 1858            })
 1859        });
 1860
 1861        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1862
 1863        let blink_manager = cx.new(|cx| {
 1864            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1865            if is_minimap {
 1866                blink_manager.disable(cx);
 1867            }
 1868            blink_manager
 1869        });
 1870
 1871        let soft_wrap_mode_override =
 1872            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1873
 1874        let mut project_subscriptions = Vec::new();
 1875        if full_mode && let Some(project) = project.as_ref() {
 1876            project_subscriptions.push(cx.subscribe_in(
 1877                project,
 1878                window,
 1879                |editor, _, event, window, cx| match event {
 1880                    project::Event::RefreshCodeLens => {
 1881                        // we always query lens with actions, without storing them, always refreshing them
 1882                    }
 1883                    project::Event::RefreshInlayHints => {
 1884                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1885                    }
 1886                    project::Event::LanguageServerAdded(..)
 1887                    | project::Event::LanguageServerRemoved(..) => {
 1888                        if editor.tasks_update_task.is_none() {
 1889                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1890                        }
 1891                    }
 1892                    project::Event::SnippetEdit(id, snippet_edits) => {
 1893                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1894                            let focus_handle = editor.focus_handle(cx);
 1895                            if focus_handle.is_focused(window) {
 1896                                let snapshot = buffer.read(cx).snapshot();
 1897                                for (range, snippet) in snippet_edits {
 1898                                    let editor_range =
 1899                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1900                                    editor
 1901                                        .insert_snippet(
 1902                                            &[editor_range],
 1903                                            snippet.clone(),
 1904                                            window,
 1905                                            cx,
 1906                                        )
 1907                                        .ok();
 1908                                }
 1909                            }
 1910                        }
 1911                    }
 1912                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1913                        let buffer_id = *buffer_id;
 1914                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1915                            let registered = editor.register_buffer(buffer_id, cx);
 1916                            if registered {
 1917                                editor.update_lsp_data(Some(buffer_id), window, cx);
 1918                                editor.refresh_inlay_hints(
 1919                                    InlayHintRefreshReason::RefreshRequested,
 1920                                    cx,
 1921                                );
 1922                                refresh_linked_ranges(editor, window, cx);
 1923                                editor.refresh_code_actions(window, cx);
 1924                                editor.refresh_document_highlights(cx);
 1925                            }
 1926                        }
 1927                    }
 1928
 1929                    project::Event::EntryRenamed(transaction) => {
 1930                        let Some(workspace) = editor.workspace() else {
 1931                            return;
 1932                        };
 1933                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1934                        else {
 1935                            return;
 1936                        };
 1937                        if active_editor.entity_id() == cx.entity_id() {
 1938                            let edited_buffers_already_open = {
 1939                                let other_editors: Vec<Entity<Editor>> = workspace
 1940                                    .read(cx)
 1941                                    .panes()
 1942                                    .iter()
 1943                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1944                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1945                                    .collect();
 1946
 1947                                transaction.0.keys().all(|buffer| {
 1948                                    other_editors.iter().any(|editor| {
 1949                                        let multi_buffer = editor.read(cx).buffer();
 1950                                        multi_buffer.read(cx).is_singleton()
 1951                                            && multi_buffer.read(cx).as_singleton().map_or(
 1952                                                false,
 1953                                                |singleton| {
 1954                                                    singleton.entity_id() == buffer.entity_id()
 1955                                                },
 1956                                            )
 1957                                    })
 1958                                })
 1959                            };
 1960
 1961                            if !edited_buffers_already_open {
 1962                                let workspace = workspace.downgrade();
 1963                                let transaction = transaction.clone();
 1964                                cx.defer_in(window, move |_, window, cx| {
 1965                                    cx.spawn_in(window, async move |editor, cx| {
 1966                                        Self::open_project_transaction(
 1967                                            &editor,
 1968                                            workspace,
 1969                                            transaction,
 1970                                            "Rename".to_string(),
 1971                                            cx,
 1972                                        )
 1973                                        .await
 1974                                        .ok()
 1975                                    })
 1976                                    .detach();
 1977                                });
 1978                            }
 1979                        }
 1980                    }
 1981
 1982                    _ => {}
 1983                },
 1984            ));
 1985            if let Some(task_inventory) = project
 1986                .read(cx)
 1987                .task_store()
 1988                .read(cx)
 1989                .task_inventory()
 1990                .cloned()
 1991            {
 1992                project_subscriptions.push(cx.observe_in(
 1993                    &task_inventory,
 1994                    window,
 1995                    |editor, _, window, cx| {
 1996                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1997                    },
 1998                ));
 1999            };
 2000
 2001            project_subscriptions.push(cx.subscribe_in(
 2002                &project.read(cx).breakpoint_store(),
 2003                window,
 2004                |editor, _, event, window, cx| match event {
 2005                    BreakpointStoreEvent::ClearDebugLines => {
 2006                        editor.clear_row_highlights::<ActiveDebugLine>();
 2007                        editor.refresh_inline_values(cx);
 2008                    }
 2009                    BreakpointStoreEvent::SetDebugLine => {
 2010                        if editor.go_to_active_debug_line(window, cx) {
 2011                            cx.stop_propagation();
 2012                        }
 2013
 2014                        editor.refresh_inline_values(cx);
 2015                    }
 2016                    _ => {}
 2017                },
 2018            ));
 2019            let git_store = project.read(cx).git_store().clone();
 2020            let project = project.clone();
 2021            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2022                if let GitStoreEvent::RepositoryUpdated(
 2023                    _,
 2024                    RepositoryEvent::Updated {
 2025                        new_instance: true, ..
 2026                    },
 2027                    _,
 2028                ) = event
 2029                {
 2030                    this.load_diff_task = Some(
 2031                        update_uncommitted_diff_for_buffer(
 2032                            cx.entity(),
 2033                            &project,
 2034                            this.buffer.read(cx).all_buffers(),
 2035                            this.buffer.clone(),
 2036                            cx,
 2037                        )
 2038                        .shared(),
 2039                    );
 2040                }
 2041            }));
 2042        }
 2043
 2044        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2045
 2046        let inlay_hint_settings =
 2047            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2048        let focus_handle = cx.focus_handle();
 2049        if !is_minimap {
 2050            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2051                .detach();
 2052            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2053                .detach();
 2054            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2055                .detach();
 2056            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2057                .detach();
 2058            cx.observe_pending_input(window, Self::observe_pending_input)
 2059                .detach();
 2060        }
 2061
 2062        let show_indent_guides =
 2063            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2064                Some(false)
 2065            } else {
 2066                None
 2067            };
 2068
 2069        let breakpoint_store = match (&mode, project.as_ref()) {
 2070            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2071            _ => None,
 2072        };
 2073
 2074        let mut code_action_providers = Vec::new();
 2075        let mut load_uncommitted_diff = None;
 2076        if let Some(project) = project.clone() {
 2077            load_uncommitted_diff = Some(
 2078                update_uncommitted_diff_for_buffer(
 2079                    cx.entity(),
 2080                    &project,
 2081                    multi_buffer.read(cx).all_buffers(),
 2082                    multi_buffer.clone(),
 2083                    cx,
 2084                )
 2085                .shared(),
 2086            );
 2087            code_action_providers.push(Rc::new(project) as Rc<_>);
 2088        }
 2089
 2090        let mut editor = Self {
 2091            focus_handle,
 2092            show_cursor_when_unfocused: false,
 2093            last_focused_descendant: None,
 2094            buffer: multi_buffer.clone(),
 2095            display_map: display_map.clone(),
 2096            placeholder_display_map: None,
 2097            selections,
 2098            scroll_manager: ScrollManager::new(cx),
 2099            columnar_selection_state: None,
 2100            add_selections_state: None,
 2101            select_next_state: None,
 2102            select_prev_state: None,
 2103            selection_history: SelectionHistory::default(),
 2104            defer_selection_effects: false,
 2105            deferred_selection_effects_state: None,
 2106            autoclose_regions: Vec::new(),
 2107            snippet_stack: InvalidationStack::default(),
 2108            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2109            ime_transaction: None,
 2110            active_diagnostics: ActiveDiagnostic::None,
 2111            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2112            inline_diagnostics_update: Task::ready(()),
 2113            inline_diagnostics: Vec::new(),
 2114            soft_wrap_mode_override,
 2115            diagnostics_max_severity,
 2116            hard_wrap: None,
 2117            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2118            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2119            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2120            project,
 2121            blink_manager: blink_manager.clone(),
 2122            show_local_selections: true,
 2123            show_scrollbars: ScrollbarAxes {
 2124                horizontal: full_mode,
 2125                vertical: full_mode,
 2126            },
 2127            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2128            offset_content: !matches!(mode, EditorMode::SingleLine),
 2129            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2130            show_gutter: full_mode,
 2131            show_line_numbers: (!full_mode).then_some(false),
 2132            use_relative_line_numbers: None,
 2133            disable_expand_excerpt_buttons: !full_mode,
 2134            show_git_diff_gutter: None,
 2135            show_code_actions: None,
 2136            show_runnables: None,
 2137            show_breakpoints: None,
 2138            show_wrap_guides: None,
 2139            show_indent_guides,
 2140            highlight_order: 0,
 2141            highlighted_rows: HashMap::default(),
 2142            background_highlights: HashMap::default(),
 2143            gutter_highlights: HashMap::default(),
 2144            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2145            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2146            nav_history: None,
 2147            context_menu: RefCell::new(None),
 2148            context_menu_options: None,
 2149            mouse_context_menu: None,
 2150            completion_tasks: Vec::new(),
 2151            inline_blame_popover: None,
 2152            inline_blame_popover_show_task: None,
 2153            signature_help_state: SignatureHelpState::default(),
 2154            auto_signature_help: None,
 2155            find_all_references_task_sources: Vec::new(),
 2156            next_completion_id: 0,
 2157            next_inlay_id: 0,
 2158            code_action_providers,
 2159            available_code_actions: None,
 2160            code_actions_task: None,
 2161            quick_selection_highlight_task: None,
 2162            debounced_selection_highlight_task: None,
 2163            document_highlights_task: None,
 2164            linked_editing_range_task: None,
 2165            pending_rename: None,
 2166            searchable: !is_minimap,
 2167            cursor_shape: EditorSettings::get_global(cx)
 2168                .cursor_shape
 2169                .unwrap_or_default(),
 2170            current_line_highlight: None,
 2171            autoindent_mode: Some(AutoindentMode::EachLine),
 2172            collapse_matches: false,
 2173            workspace: None,
 2174            input_enabled: !is_minimap,
 2175            use_modal_editing: full_mode,
 2176            read_only: is_minimap,
 2177            use_autoclose: true,
 2178            use_auto_surround: true,
 2179            auto_replace_emoji_shortcode: false,
 2180            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2181            leader_id: None,
 2182            remote_id: None,
 2183            hover_state: HoverState::default(),
 2184            pending_mouse_down: None,
 2185            hovered_link_state: None,
 2186            edit_prediction_provider: None,
 2187            active_edit_prediction: None,
 2188            stale_edit_prediction_in_menu: None,
 2189            edit_prediction_preview: EditPredictionPreview::Inactive {
 2190                released_too_fast: false,
 2191            },
 2192            inline_diagnostics_enabled: full_mode,
 2193            diagnostics_enabled: full_mode,
 2194            word_completions_enabled: full_mode,
 2195            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2196            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2197            gutter_hovered: false,
 2198            pixel_position_of_newest_cursor: None,
 2199            last_bounds: None,
 2200            last_position_map: None,
 2201            expect_bounds_change: None,
 2202            gutter_dimensions: GutterDimensions::default(),
 2203            style: None,
 2204            show_cursor_names: false,
 2205            hovered_cursors: HashMap::default(),
 2206            next_editor_action_id: EditorActionId::default(),
 2207            editor_actions: Rc::default(),
 2208            edit_predictions_hidden_for_vim_mode: false,
 2209            show_edit_predictions_override: None,
 2210            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2211            edit_prediction_settings: EditPredictionSettings::Disabled,
 2212            edit_prediction_indent_conflict: false,
 2213            edit_prediction_requires_modifier_in_indent_conflict: true,
 2214            custom_context_menu: None,
 2215            show_git_blame_gutter: false,
 2216            show_git_blame_inline: false,
 2217            show_selection_menu: None,
 2218            show_git_blame_inline_delay_task: None,
 2219            git_blame_inline_enabled: full_mode
 2220                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2221            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2222            serialize_dirty_buffers: !is_minimap
 2223                && ProjectSettings::get_global(cx)
 2224                    .session
 2225                    .restore_unsaved_buffers,
 2226            blame: None,
 2227            blame_subscription: None,
 2228            tasks: BTreeMap::default(),
 2229
 2230            breakpoint_store,
 2231            gutter_breakpoint_indicator: (None, None),
 2232            hovered_diff_hunk_row: None,
 2233            _subscriptions: (!is_minimap)
 2234                .then(|| {
 2235                    vec![
 2236                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2237                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2238                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2239                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2240                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2241                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2242                        cx.observe_window_activation(window, |editor, window, cx| {
 2243                            let active = window.is_window_active();
 2244                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2245                                if active {
 2246                                    blink_manager.enable(cx);
 2247                                } else {
 2248                                    blink_manager.disable(cx);
 2249                                }
 2250                            });
 2251                            if active {
 2252                                editor.show_mouse_cursor(cx);
 2253                            }
 2254                        }),
 2255                    ]
 2256                })
 2257                .unwrap_or_default(),
 2258            tasks_update_task: None,
 2259            pull_diagnostics_task: Task::ready(()),
 2260            colors: None,
 2261            refresh_colors_task: Task::ready(()),
 2262            next_color_inlay_id: 0,
 2263            post_scroll_update: Task::ready(()),
 2264            linked_edit_ranges: Default::default(),
 2265            in_project_search: false,
 2266            previous_search_ranges: None,
 2267            breadcrumb_header: None,
 2268            focused_block: None,
 2269            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2270            addons: HashMap::default(),
 2271            registered_buffers: HashMap::default(),
 2272            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2273            selection_mark_mode: false,
 2274            toggle_fold_multiple_buffers: Task::ready(()),
 2275            serialize_selections: Task::ready(()),
 2276            serialize_folds: Task::ready(()),
 2277            text_style_refinement: None,
 2278            load_diff_task: load_uncommitted_diff,
 2279            temporary_diff_override: false,
 2280            mouse_cursor_hidden: false,
 2281            minimap: None,
 2282            hide_mouse_mode: EditorSettings::get_global(cx)
 2283                .hide_mouse
 2284                .unwrap_or_default(),
 2285            change_list: ChangeList::new(),
 2286            mode,
 2287            selection_drag_state: SelectionDragState::None,
 2288            folding_newlines: Task::ready(()),
 2289            lookup_key: None,
 2290        };
 2291
 2292        if is_minimap {
 2293            return editor;
 2294        }
 2295
 2296        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2297            editor
 2298                ._subscriptions
 2299                .push(cx.observe(breakpoints, |_, _, cx| {
 2300                    cx.notify();
 2301                }));
 2302        }
 2303        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2304        editor._subscriptions.extend(project_subscriptions);
 2305
 2306        editor._subscriptions.push(cx.subscribe_in(
 2307            &cx.entity(),
 2308            window,
 2309            |editor, _, e: &EditorEvent, window, cx| match e {
 2310                EditorEvent::ScrollPositionChanged { local, .. } => {
 2311                    if *local {
 2312                        let new_anchor = editor.scroll_manager.anchor();
 2313                        let snapshot = editor.snapshot(window, cx);
 2314                        editor.update_restoration_data(cx, move |data| {
 2315                            data.scroll_position = (
 2316                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2317                                new_anchor.offset,
 2318                            );
 2319                        });
 2320                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2321                        editor.inline_blame_popover.take();
 2322                    }
 2323                }
 2324                EditorEvent::Edited { .. } => {
 2325                    if !vim_enabled(cx) {
 2326                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2327                        let pop_state = editor
 2328                            .change_list
 2329                            .last()
 2330                            .map(|previous| {
 2331                                previous.len() == selections.len()
 2332                                    && previous.iter().enumerate().all(|(ix, p)| {
 2333                                        p.to_display_point(&map).row()
 2334                                            == selections[ix].head().row()
 2335                                    })
 2336                            })
 2337                            .unwrap_or(false);
 2338                        let new_positions = selections
 2339                            .into_iter()
 2340                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2341                            .collect();
 2342                        editor
 2343                            .change_list
 2344                            .push_to_change_list(pop_state, new_positions);
 2345                    }
 2346                }
 2347                _ => (),
 2348            },
 2349        ));
 2350
 2351        if let Some(dap_store) = editor
 2352            .project
 2353            .as_ref()
 2354            .map(|project| project.read(cx).dap_store())
 2355        {
 2356            let weak_editor = cx.weak_entity();
 2357
 2358            editor
 2359                ._subscriptions
 2360                .push(
 2361                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2362                        let session_entity = cx.entity();
 2363                        weak_editor
 2364                            .update(cx, |editor, cx| {
 2365                                editor._subscriptions.push(
 2366                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2367                                );
 2368                            })
 2369                            .ok();
 2370                    }),
 2371                );
 2372
 2373            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2374                editor
 2375                    ._subscriptions
 2376                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2377            }
 2378        }
 2379
 2380        // skip adding the initial selection to selection history
 2381        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2382        editor.end_selection(window, cx);
 2383        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2384
 2385        editor.scroll_manager.show_scrollbars(window, cx);
 2386        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2387
 2388        if full_mode {
 2389            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2390            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2391
 2392            if editor.git_blame_inline_enabled {
 2393                editor.start_git_blame_inline(false, window, cx);
 2394            }
 2395
 2396            editor.go_to_active_debug_line(window, cx);
 2397
 2398            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2399                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2400            }
 2401
 2402            editor.minimap =
 2403                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2404            editor.colors = Some(LspColorData::new(cx));
 2405            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2406        }
 2407
 2408        editor
 2409    }
 2410
 2411    pub fn deploy_mouse_context_menu(
 2412        &mut self,
 2413        position: gpui::Point<Pixels>,
 2414        context_menu: Entity<ContextMenu>,
 2415        window: &mut Window,
 2416        cx: &mut Context<Self>,
 2417    ) {
 2418        self.mouse_context_menu = Some(MouseContextMenu::new(
 2419            self,
 2420            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2421            context_menu,
 2422            window,
 2423            cx,
 2424        ));
 2425    }
 2426
 2427    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2428        self.mouse_context_menu
 2429            .as_ref()
 2430            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2431    }
 2432
 2433    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2434        if self
 2435            .selections
 2436            .pending_anchor()
 2437            .is_some_and(|pending_selection| {
 2438                let snapshot = self.buffer().read(cx).snapshot(cx);
 2439                pending_selection.range().includes(range, &snapshot)
 2440            })
 2441        {
 2442            return true;
 2443        }
 2444
 2445        self.selections
 2446            .disjoint_in_range::<usize>(range.clone(), cx)
 2447            .into_iter()
 2448            .any(|selection| {
 2449                // This is needed to cover a corner case, if we just check for an existing
 2450                // selection in the fold range, having a cursor at the start of the fold
 2451                // marks it as selected. Non-empty selections don't cause this.
 2452                let length = selection.end - selection.start;
 2453                length > 0
 2454            })
 2455    }
 2456
 2457    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2458        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2459    }
 2460
 2461    fn key_context_internal(
 2462        &self,
 2463        has_active_edit_prediction: bool,
 2464        window: &Window,
 2465        cx: &App,
 2466    ) -> KeyContext {
 2467        let mut key_context = KeyContext::new_with_defaults();
 2468        key_context.add("Editor");
 2469        let mode = match self.mode {
 2470            EditorMode::SingleLine => "single_line",
 2471            EditorMode::AutoHeight { .. } => "auto_height",
 2472            EditorMode::Minimap { .. } => "minimap",
 2473            EditorMode::Full { .. } => "full",
 2474        };
 2475
 2476        if EditorSettings::jupyter_enabled(cx) {
 2477            key_context.add("jupyter");
 2478        }
 2479
 2480        key_context.set("mode", mode);
 2481        if self.pending_rename.is_some() {
 2482            key_context.add("renaming");
 2483        }
 2484
 2485        match self.context_menu.borrow().as_ref() {
 2486            Some(CodeContextMenu::Completions(menu)) => {
 2487                if menu.visible() {
 2488                    key_context.add("menu");
 2489                    key_context.add("showing_completions");
 2490                }
 2491            }
 2492            Some(CodeContextMenu::CodeActions(menu)) => {
 2493                if menu.visible() {
 2494                    key_context.add("menu");
 2495                    key_context.add("showing_code_actions")
 2496                }
 2497            }
 2498            None => {}
 2499        }
 2500
 2501        if self.signature_help_state.has_multiple_signatures() {
 2502            key_context.add("showing_signature_help");
 2503        }
 2504
 2505        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2506        if !self.focus_handle(cx).contains_focused(window, cx)
 2507            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2508        {
 2509            for addon in self.addons.values() {
 2510                addon.extend_key_context(&mut key_context, cx)
 2511            }
 2512        }
 2513
 2514        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2515            if let Some(extension) = singleton_buffer
 2516                .read(cx)
 2517                .file()
 2518                .and_then(|file| file.path().extension())
 2519            {
 2520                key_context.set("extension", extension.to_string());
 2521            }
 2522        } else {
 2523            key_context.add("multibuffer");
 2524        }
 2525
 2526        if has_active_edit_prediction {
 2527            if self.edit_prediction_in_conflict() {
 2528                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2529            } else {
 2530                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2531                key_context.add("copilot_suggestion");
 2532            }
 2533        }
 2534
 2535        if self.selection_mark_mode {
 2536            key_context.add("selection_mode");
 2537        }
 2538
 2539        key_context
 2540    }
 2541
 2542    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2543        self.last_bounds.as_ref()
 2544    }
 2545
 2546    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2547        if self.mouse_cursor_hidden {
 2548            self.mouse_cursor_hidden = false;
 2549            cx.notify();
 2550        }
 2551    }
 2552
 2553    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2554        let hide_mouse_cursor = match origin {
 2555            HideMouseCursorOrigin::TypingAction => {
 2556                matches!(
 2557                    self.hide_mouse_mode,
 2558                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2559                )
 2560            }
 2561            HideMouseCursorOrigin::MovementAction => {
 2562                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2563            }
 2564        };
 2565        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2566            self.mouse_cursor_hidden = hide_mouse_cursor;
 2567            cx.notify();
 2568        }
 2569    }
 2570
 2571    pub fn edit_prediction_in_conflict(&self) -> bool {
 2572        if !self.show_edit_predictions_in_menu() {
 2573            return false;
 2574        }
 2575
 2576        let showing_completions = self
 2577            .context_menu
 2578            .borrow()
 2579            .as_ref()
 2580            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2581
 2582        showing_completions
 2583            || self.edit_prediction_requires_modifier()
 2584            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2585            // bindings to insert tab characters.
 2586            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2587    }
 2588
 2589    pub fn accept_edit_prediction_keybind(
 2590        &self,
 2591        accept_partial: bool,
 2592        window: &Window,
 2593        cx: &App,
 2594    ) -> AcceptEditPredictionBinding {
 2595        let key_context = self.key_context_internal(true, window, cx);
 2596        let in_conflict = self.edit_prediction_in_conflict();
 2597
 2598        let bindings = if accept_partial {
 2599            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2600        } else {
 2601            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2602        };
 2603
 2604        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2605        // just the first one.
 2606        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2607            !in_conflict
 2608                || binding
 2609                    .keystrokes()
 2610                    .first()
 2611                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2612        }))
 2613    }
 2614
 2615    pub fn new_file(
 2616        workspace: &mut Workspace,
 2617        _: &workspace::NewFile,
 2618        window: &mut Window,
 2619        cx: &mut Context<Workspace>,
 2620    ) {
 2621        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2622            "Failed to create buffer",
 2623            window,
 2624            cx,
 2625            |e, _, _| match e.error_code() {
 2626                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2627                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2628                e.error_tag("required").unwrap_or("the latest version")
 2629            )),
 2630                _ => None,
 2631            },
 2632        );
 2633    }
 2634
 2635    pub fn new_in_workspace(
 2636        workspace: &mut Workspace,
 2637        window: &mut Window,
 2638        cx: &mut Context<Workspace>,
 2639    ) -> Task<Result<Entity<Editor>>> {
 2640        let project = workspace.project().clone();
 2641        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2642
 2643        cx.spawn_in(window, async move |workspace, cx| {
 2644            let buffer = create.await?;
 2645            workspace.update_in(cx, |workspace, window, cx| {
 2646                let editor =
 2647                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2648                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2649                editor
 2650            })
 2651        })
 2652    }
 2653
 2654    fn new_file_vertical(
 2655        workspace: &mut Workspace,
 2656        _: &workspace::NewFileSplitVertical,
 2657        window: &mut Window,
 2658        cx: &mut Context<Workspace>,
 2659    ) {
 2660        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2661    }
 2662
 2663    fn new_file_horizontal(
 2664        workspace: &mut Workspace,
 2665        _: &workspace::NewFileSplitHorizontal,
 2666        window: &mut Window,
 2667        cx: &mut Context<Workspace>,
 2668    ) {
 2669        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2670    }
 2671
 2672    fn new_file_in_direction(
 2673        workspace: &mut Workspace,
 2674        direction: SplitDirection,
 2675        window: &mut Window,
 2676        cx: &mut Context<Workspace>,
 2677    ) {
 2678        let project = workspace.project().clone();
 2679        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2680
 2681        cx.spawn_in(window, async move |workspace, cx| {
 2682            let buffer = create.await?;
 2683            workspace.update_in(cx, move |workspace, window, cx| {
 2684                workspace.split_item(
 2685                    direction,
 2686                    Box::new(
 2687                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2688                    ),
 2689                    window,
 2690                    cx,
 2691                )
 2692            })?;
 2693            anyhow::Ok(())
 2694        })
 2695        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2696            match e.error_code() {
 2697                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2698                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2699                e.error_tag("required").unwrap_or("the latest version")
 2700            )),
 2701                _ => None,
 2702            }
 2703        });
 2704    }
 2705
 2706    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2707        self.leader_id
 2708    }
 2709
 2710    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2711        &self.buffer
 2712    }
 2713
 2714    pub fn project(&self) -> Option<&Entity<Project>> {
 2715        self.project.as_ref()
 2716    }
 2717
 2718    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2719        self.workspace.as_ref()?.0.upgrade()
 2720    }
 2721
 2722    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2723        self.buffer().read(cx).title(cx)
 2724    }
 2725
 2726    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2727        let git_blame_gutter_max_author_length = self
 2728            .render_git_blame_gutter(cx)
 2729            .then(|| {
 2730                if let Some(blame) = self.blame.as_ref() {
 2731                    let max_author_length =
 2732                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2733                    Some(max_author_length)
 2734                } else {
 2735                    None
 2736                }
 2737            })
 2738            .flatten();
 2739
 2740        EditorSnapshot {
 2741            mode: self.mode.clone(),
 2742            show_gutter: self.show_gutter,
 2743            show_line_numbers: self.show_line_numbers,
 2744            show_git_diff_gutter: self.show_git_diff_gutter,
 2745            show_code_actions: self.show_code_actions,
 2746            show_runnables: self.show_runnables,
 2747            show_breakpoints: self.show_breakpoints,
 2748            git_blame_gutter_max_author_length,
 2749            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2750            placeholder_display_snapshot: self
 2751                .placeholder_display_map
 2752                .as_ref()
 2753                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2754            scroll_anchor: self.scroll_manager.anchor(),
 2755            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2756            is_focused: self.focus_handle.is_focused(window),
 2757            current_line_highlight: self
 2758                .current_line_highlight
 2759                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2760            gutter_hovered: self.gutter_hovered,
 2761        }
 2762    }
 2763
 2764    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2765        self.buffer.read(cx).language_at(point, cx)
 2766    }
 2767
 2768    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2769        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2770    }
 2771
 2772    pub fn active_excerpt(
 2773        &self,
 2774        cx: &App,
 2775    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2776        self.buffer
 2777            .read(cx)
 2778            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2779    }
 2780
 2781    pub fn mode(&self) -> &EditorMode {
 2782        &self.mode
 2783    }
 2784
 2785    pub fn set_mode(&mut self, mode: EditorMode) {
 2786        self.mode = mode;
 2787    }
 2788
 2789    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2790        self.collaboration_hub.as_deref()
 2791    }
 2792
 2793    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2794        self.collaboration_hub = Some(hub);
 2795    }
 2796
 2797    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2798        self.in_project_search = in_project_search;
 2799    }
 2800
 2801    pub fn set_custom_context_menu(
 2802        &mut self,
 2803        f: impl 'static
 2804        + Fn(
 2805            &mut Self,
 2806            DisplayPoint,
 2807            &mut Window,
 2808            &mut Context<Self>,
 2809        ) -> Option<Entity<ui::ContextMenu>>,
 2810    ) {
 2811        self.custom_context_menu = Some(Box::new(f))
 2812    }
 2813
 2814    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2815        self.completion_provider = provider;
 2816    }
 2817
 2818    #[cfg(any(test, feature = "test-support"))]
 2819    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2820        self.completion_provider.clone()
 2821    }
 2822
 2823    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2824        self.semantics_provider.clone()
 2825    }
 2826
 2827    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2828        self.semantics_provider = provider;
 2829    }
 2830
 2831    pub fn set_edit_prediction_provider<T>(
 2832        &mut self,
 2833        provider: Option<Entity<T>>,
 2834        window: &mut Window,
 2835        cx: &mut Context<Self>,
 2836    ) where
 2837        T: EditPredictionProvider,
 2838    {
 2839        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2840            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2841                if this.focus_handle.is_focused(window) {
 2842                    this.update_visible_edit_prediction(window, cx);
 2843                }
 2844            }),
 2845            provider: Arc::new(provider),
 2846        });
 2847        self.update_edit_prediction_settings(cx);
 2848        self.refresh_edit_prediction(false, false, window, cx);
 2849    }
 2850
 2851    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2852        self.placeholder_display_map
 2853            .as_ref()
 2854            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2855    }
 2856
 2857    pub fn set_placeholder_text(
 2858        &mut self,
 2859        placeholder_text: &str,
 2860        window: &mut Window,
 2861        cx: &mut Context<Self>,
 2862    ) {
 2863        let multibuffer = cx
 2864            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2865
 2866        let style = window.text_style();
 2867
 2868        self.placeholder_display_map = Some(cx.new(|cx| {
 2869            DisplayMap::new(
 2870                multibuffer,
 2871                style.font(),
 2872                style.font_size.to_pixels(window.rem_size()),
 2873                None,
 2874                FILE_HEADER_HEIGHT,
 2875                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2876                Default::default(),
 2877                DiagnosticSeverity::Off,
 2878                cx,
 2879            )
 2880        }));
 2881        cx.notify();
 2882    }
 2883
 2884    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2885        self.cursor_shape = cursor_shape;
 2886
 2887        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2888        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2889
 2890        cx.notify();
 2891    }
 2892
 2893    pub fn set_current_line_highlight(
 2894        &mut self,
 2895        current_line_highlight: Option<CurrentLineHighlight>,
 2896    ) {
 2897        self.current_line_highlight = current_line_highlight;
 2898    }
 2899
 2900    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2901        self.collapse_matches = collapse_matches;
 2902    }
 2903
 2904    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2905        if self.collapse_matches {
 2906            return range.start..range.start;
 2907        }
 2908        range.clone()
 2909    }
 2910
 2911    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2912        if self.display_map.read(cx).clip_at_line_ends != clip {
 2913            self.display_map
 2914                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2915        }
 2916    }
 2917
 2918    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2919        self.input_enabled = input_enabled;
 2920    }
 2921
 2922    pub fn set_edit_predictions_hidden_for_vim_mode(
 2923        &mut self,
 2924        hidden: bool,
 2925        window: &mut Window,
 2926        cx: &mut Context<Self>,
 2927    ) {
 2928        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2929            self.edit_predictions_hidden_for_vim_mode = hidden;
 2930            if hidden {
 2931                self.update_visible_edit_prediction(window, cx);
 2932            } else {
 2933                self.refresh_edit_prediction(true, false, window, cx);
 2934            }
 2935        }
 2936    }
 2937
 2938    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2939        self.menu_edit_predictions_policy = value;
 2940    }
 2941
 2942    pub fn set_autoindent(&mut self, autoindent: bool) {
 2943        if autoindent {
 2944            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2945        } else {
 2946            self.autoindent_mode = None;
 2947        }
 2948    }
 2949
 2950    pub fn read_only(&self, cx: &App) -> bool {
 2951        self.read_only || self.buffer.read(cx).read_only()
 2952    }
 2953
 2954    pub fn set_read_only(&mut self, read_only: bool) {
 2955        self.read_only = read_only;
 2956    }
 2957
 2958    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2959        self.use_autoclose = autoclose;
 2960    }
 2961
 2962    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2963        self.use_auto_surround = auto_surround;
 2964    }
 2965
 2966    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2967        self.auto_replace_emoji_shortcode = auto_replace;
 2968    }
 2969
 2970    pub fn toggle_edit_predictions(
 2971        &mut self,
 2972        _: &ToggleEditPrediction,
 2973        window: &mut Window,
 2974        cx: &mut Context<Self>,
 2975    ) {
 2976        if self.show_edit_predictions_override.is_some() {
 2977            self.set_show_edit_predictions(None, window, cx);
 2978        } else {
 2979            let show_edit_predictions = !self.edit_predictions_enabled();
 2980            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2981        }
 2982    }
 2983
 2984    pub fn set_show_edit_predictions(
 2985        &mut self,
 2986        show_edit_predictions: Option<bool>,
 2987        window: &mut Window,
 2988        cx: &mut Context<Self>,
 2989    ) {
 2990        self.show_edit_predictions_override = show_edit_predictions;
 2991        self.update_edit_prediction_settings(cx);
 2992
 2993        if let Some(false) = show_edit_predictions {
 2994            self.discard_edit_prediction(false, cx);
 2995        } else {
 2996            self.refresh_edit_prediction(false, true, window, cx);
 2997        }
 2998    }
 2999
 3000    fn edit_predictions_disabled_in_scope(
 3001        &self,
 3002        buffer: &Entity<Buffer>,
 3003        buffer_position: language::Anchor,
 3004        cx: &App,
 3005    ) -> bool {
 3006        let snapshot = buffer.read(cx).snapshot();
 3007        let settings = snapshot.settings_at(buffer_position, cx);
 3008
 3009        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3010            return false;
 3011        };
 3012
 3013        scope.override_name().is_some_and(|scope_name| {
 3014            settings
 3015                .edit_predictions_disabled_in
 3016                .iter()
 3017                .any(|s| s == scope_name)
 3018        })
 3019    }
 3020
 3021    pub fn set_use_modal_editing(&mut self, to: bool) {
 3022        self.use_modal_editing = to;
 3023    }
 3024
 3025    pub fn use_modal_editing(&self) -> bool {
 3026        self.use_modal_editing
 3027    }
 3028
 3029    fn selections_did_change(
 3030        &mut self,
 3031        local: bool,
 3032        old_cursor_position: &Anchor,
 3033        effects: SelectionEffects,
 3034        window: &mut Window,
 3035        cx: &mut Context<Self>,
 3036    ) {
 3037        window.invalidate_character_coordinates();
 3038
 3039        // Copy selections to primary selection buffer
 3040        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3041        if local {
 3042            let selections = self.selections.all::<usize>(cx);
 3043            let buffer_handle = self.buffer.read(cx).read(cx);
 3044
 3045            let mut text = String::new();
 3046            for (index, selection) in selections.iter().enumerate() {
 3047                let text_for_selection = buffer_handle
 3048                    .text_for_range(selection.start..selection.end)
 3049                    .collect::<String>();
 3050
 3051                text.push_str(&text_for_selection);
 3052                if index != selections.len() - 1 {
 3053                    text.push('\n');
 3054                }
 3055            }
 3056
 3057            if !text.is_empty() {
 3058                cx.write_to_primary(ClipboardItem::new_string(text));
 3059            }
 3060        }
 3061
 3062        let selection_anchors = self.selections.disjoint_anchors_arc();
 3063
 3064        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3065            self.buffer.update(cx, |buffer, cx| {
 3066                buffer.set_active_selections(
 3067                    &selection_anchors,
 3068                    self.selections.line_mode(),
 3069                    self.cursor_shape,
 3070                    cx,
 3071                )
 3072            });
 3073        }
 3074        let display_map = self
 3075            .display_map
 3076            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3077        let buffer = display_map.buffer_snapshot();
 3078        if self.selections.count() == 1 {
 3079            self.add_selections_state = None;
 3080        }
 3081        self.select_next_state = None;
 3082        self.select_prev_state = None;
 3083        self.select_syntax_node_history.try_clear();
 3084        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3085        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3086        self.take_rename(false, window, cx);
 3087
 3088        let newest_selection = self.selections.newest_anchor();
 3089        let new_cursor_position = newest_selection.head();
 3090        let selection_start = newest_selection.start;
 3091
 3092        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3093            self.push_to_nav_history(
 3094                *old_cursor_position,
 3095                Some(new_cursor_position.to_point(buffer)),
 3096                false,
 3097                effects.nav_history == Some(true),
 3098                cx,
 3099            );
 3100        }
 3101
 3102        if local {
 3103            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3104                self.register_buffer(buffer_id, cx);
 3105            }
 3106
 3107            let mut context_menu = self.context_menu.borrow_mut();
 3108            let completion_menu = match context_menu.as_ref() {
 3109                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3110                Some(CodeContextMenu::CodeActions(_)) => {
 3111                    *context_menu = None;
 3112                    None
 3113                }
 3114                None => None,
 3115            };
 3116            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3117            drop(context_menu);
 3118
 3119            if effects.completions
 3120                && let Some(completion_position) = completion_position
 3121            {
 3122                let start_offset = selection_start.to_offset(buffer);
 3123                let position_matches = start_offset == completion_position.to_offset(buffer);
 3124                let continue_showing = if position_matches {
 3125                    if self.snippet_stack.is_empty() {
 3126                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3127                            == Some(CharKind::Word)
 3128                    } else {
 3129                        // Snippet choices can be shown even when the cursor is in whitespace.
 3130                        // Dismissing the menu with actions like backspace is handled by
 3131                        // invalidation regions.
 3132                        true
 3133                    }
 3134                } else {
 3135                    false
 3136                };
 3137
 3138                if continue_showing {
 3139                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3140                } else {
 3141                    self.hide_context_menu(window, cx);
 3142                }
 3143            }
 3144
 3145            hide_hover(self, cx);
 3146
 3147            if old_cursor_position.to_display_point(&display_map).row()
 3148                != new_cursor_position.to_display_point(&display_map).row()
 3149            {
 3150                self.available_code_actions.take();
 3151            }
 3152            self.refresh_code_actions(window, cx);
 3153            self.refresh_document_highlights(cx);
 3154            refresh_linked_ranges(self, window, cx);
 3155
 3156            self.refresh_selected_text_highlights(false, window, cx);
 3157            refresh_matching_bracket_highlights(self, cx);
 3158            self.update_visible_edit_prediction(window, cx);
 3159            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3160            self.inline_blame_popover.take();
 3161            if self.git_blame_inline_enabled {
 3162                self.start_inline_blame_timer(window, cx);
 3163            }
 3164        }
 3165
 3166        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3167        cx.emit(EditorEvent::SelectionsChanged { local });
 3168
 3169        let selections = &self.selections.disjoint_anchors_arc();
 3170        if selections.len() == 1 {
 3171            cx.emit(SearchEvent::ActiveMatchChanged)
 3172        }
 3173        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3174            let inmemory_selections = selections
 3175                .iter()
 3176                .map(|s| {
 3177                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3178                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3179                })
 3180                .collect();
 3181            self.update_restoration_data(cx, |data| {
 3182                data.selections = inmemory_selections;
 3183            });
 3184
 3185            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3186                && let Some(workspace_id) =
 3187                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3188            {
 3189                let snapshot = self.buffer().read(cx).snapshot(cx);
 3190                let selections = selections.clone();
 3191                let background_executor = cx.background_executor().clone();
 3192                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3193                self.serialize_selections = cx.background_spawn(async move {
 3194                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3195                    let db_selections = selections
 3196                        .iter()
 3197                        .map(|selection| {
 3198                            (
 3199                                selection.start.to_offset(&snapshot),
 3200                                selection.end.to_offset(&snapshot),
 3201                            )
 3202                        })
 3203                        .collect();
 3204
 3205                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3206                        .await
 3207                        .with_context(|| {
 3208                            format!(
 3209                                "persisting editor selections for editor {editor_id}, \
 3210                                workspace {workspace_id:?}"
 3211                            )
 3212                        })
 3213                        .log_err();
 3214                });
 3215            }
 3216        }
 3217
 3218        cx.notify();
 3219    }
 3220
 3221    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3222        use text::ToOffset as _;
 3223        use text::ToPoint as _;
 3224
 3225        if self.mode.is_minimap()
 3226            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3227        {
 3228            return;
 3229        }
 3230
 3231        if !self.buffer().read(cx).is_singleton() {
 3232            return;
 3233        }
 3234
 3235        let display_snapshot = self
 3236            .display_map
 3237            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3238        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3239            return;
 3240        };
 3241        let inmemory_folds = display_snapshot
 3242            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3243            .map(|fold| {
 3244                fold.range.start.text_anchor.to_point(&snapshot)
 3245                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3246            })
 3247            .collect();
 3248        self.update_restoration_data(cx, |data| {
 3249            data.folds = inmemory_folds;
 3250        });
 3251
 3252        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3253            return;
 3254        };
 3255        let background_executor = cx.background_executor().clone();
 3256        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3257        let db_folds = display_snapshot
 3258            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3259            .map(|fold| {
 3260                (
 3261                    fold.range.start.text_anchor.to_offset(&snapshot),
 3262                    fold.range.end.text_anchor.to_offset(&snapshot),
 3263                )
 3264            })
 3265            .collect();
 3266        self.serialize_folds = cx.background_spawn(async move {
 3267            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3268            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3269                .await
 3270                .with_context(|| {
 3271                    format!(
 3272                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3273                    )
 3274                })
 3275                .log_err();
 3276        });
 3277    }
 3278
 3279    pub fn sync_selections(
 3280        &mut self,
 3281        other: Entity<Editor>,
 3282        cx: &mut Context<Self>,
 3283    ) -> gpui::Subscription {
 3284        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3285        if !other_selections.is_empty() {
 3286            self.selections.change_with(cx, |selections| {
 3287                selections.select_anchors(other_selections);
 3288            });
 3289        }
 3290
 3291        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3292            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3293                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3294                if other_selections.is_empty() {
 3295                    return;
 3296                }
 3297                this.selections.change_with(cx, |selections| {
 3298                    selections.select_anchors(other_selections);
 3299                });
 3300            }
 3301        });
 3302
 3303        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3304            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3305                let these_selections = this.selections.disjoint_anchors().to_vec();
 3306                if these_selections.is_empty() {
 3307                    return;
 3308                }
 3309                other.update(cx, |other_editor, cx| {
 3310                    other_editor.selections.change_with(cx, |selections| {
 3311                        selections.select_anchors(these_selections);
 3312                    })
 3313                });
 3314            }
 3315        });
 3316
 3317        Subscription::join(other_subscription, this_subscription)
 3318    }
 3319
 3320    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3321    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3322    /// effects of selection change occur at the end of the transaction.
 3323    pub fn change_selections<R>(
 3324        &mut self,
 3325        effects: SelectionEffects,
 3326        window: &mut Window,
 3327        cx: &mut Context<Self>,
 3328        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3329    ) -> R {
 3330        if let Some(state) = &mut self.deferred_selection_effects_state {
 3331            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3332            state.effects.completions = effects.completions;
 3333            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3334            let (changed, result) = self.selections.change_with(cx, change);
 3335            state.changed |= changed;
 3336            return result;
 3337        }
 3338        let mut state = DeferredSelectionEffectsState {
 3339            changed: false,
 3340            effects,
 3341            old_cursor_position: self.selections.newest_anchor().head(),
 3342            history_entry: SelectionHistoryEntry {
 3343                selections: self.selections.disjoint_anchors_arc(),
 3344                select_next_state: self.select_next_state.clone(),
 3345                select_prev_state: self.select_prev_state.clone(),
 3346                add_selections_state: self.add_selections_state.clone(),
 3347            },
 3348        };
 3349        let (changed, result) = self.selections.change_with(cx, change);
 3350        state.changed = state.changed || changed;
 3351        if self.defer_selection_effects {
 3352            self.deferred_selection_effects_state = Some(state);
 3353        } else {
 3354            self.apply_selection_effects(state, window, cx);
 3355        }
 3356        result
 3357    }
 3358
 3359    /// Defers the effects of selection change, so that the effects of multiple calls to
 3360    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3361    /// to selection history and the state of popovers based on selection position aren't
 3362    /// erroneously updated.
 3363    pub fn with_selection_effects_deferred<R>(
 3364        &mut self,
 3365        window: &mut Window,
 3366        cx: &mut Context<Self>,
 3367        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3368    ) -> R {
 3369        let already_deferred = self.defer_selection_effects;
 3370        self.defer_selection_effects = true;
 3371        let result = update(self, window, cx);
 3372        if !already_deferred {
 3373            self.defer_selection_effects = false;
 3374            if let Some(state) = self.deferred_selection_effects_state.take() {
 3375                self.apply_selection_effects(state, window, cx);
 3376            }
 3377        }
 3378        result
 3379    }
 3380
 3381    fn apply_selection_effects(
 3382        &mut self,
 3383        state: DeferredSelectionEffectsState,
 3384        window: &mut Window,
 3385        cx: &mut Context<Self>,
 3386    ) {
 3387        if state.changed {
 3388            self.selection_history.push(state.history_entry);
 3389
 3390            if let Some(autoscroll) = state.effects.scroll {
 3391                self.request_autoscroll(autoscroll, cx);
 3392            }
 3393
 3394            let old_cursor_position = &state.old_cursor_position;
 3395
 3396            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3397
 3398            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3399                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3400            }
 3401        }
 3402    }
 3403
 3404    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3405    where
 3406        I: IntoIterator<Item = (Range<S>, T)>,
 3407        S: ToOffset,
 3408        T: Into<Arc<str>>,
 3409    {
 3410        if self.read_only(cx) {
 3411            return;
 3412        }
 3413
 3414        self.buffer
 3415            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3416    }
 3417
 3418    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3419    where
 3420        I: IntoIterator<Item = (Range<S>, T)>,
 3421        S: ToOffset,
 3422        T: Into<Arc<str>>,
 3423    {
 3424        if self.read_only(cx) {
 3425            return;
 3426        }
 3427
 3428        self.buffer.update(cx, |buffer, cx| {
 3429            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3430        });
 3431    }
 3432
 3433    pub fn edit_with_block_indent<I, S, T>(
 3434        &mut self,
 3435        edits: I,
 3436        original_indent_columns: Vec<Option<u32>>,
 3437        cx: &mut Context<Self>,
 3438    ) where
 3439        I: IntoIterator<Item = (Range<S>, T)>,
 3440        S: ToOffset,
 3441        T: Into<Arc<str>>,
 3442    {
 3443        if self.read_only(cx) {
 3444            return;
 3445        }
 3446
 3447        self.buffer.update(cx, |buffer, cx| {
 3448            buffer.edit(
 3449                edits,
 3450                Some(AutoindentMode::Block {
 3451                    original_indent_columns,
 3452                }),
 3453                cx,
 3454            )
 3455        });
 3456    }
 3457
 3458    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3459        self.hide_context_menu(window, cx);
 3460
 3461        match phase {
 3462            SelectPhase::Begin {
 3463                position,
 3464                add,
 3465                click_count,
 3466            } => self.begin_selection(position, add, click_count, window, cx),
 3467            SelectPhase::BeginColumnar {
 3468                position,
 3469                goal_column,
 3470                reset,
 3471                mode,
 3472            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3473            SelectPhase::Extend {
 3474                position,
 3475                click_count,
 3476            } => self.extend_selection(position, click_count, window, cx),
 3477            SelectPhase::Update {
 3478                position,
 3479                goal_column,
 3480                scroll_delta,
 3481            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3482            SelectPhase::End => self.end_selection(window, cx),
 3483        }
 3484    }
 3485
 3486    fn extend_selection(
 3487        &mut self,
 3488        position: DisplayPoint,
 3489        click_count: usize,
 3490        window: &mut Window,
 3491        cx: &mut Context<Self>,
 3492    ) {
 3493        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3494        let tail = self.selections.newest::<usize>(cx).tail();
 3495        let click_count = click_count.max(match self.selections.select_mode() {
 3496            SelectMode::Character => 1,
 3497            SelectMode::Word(_) => 2,
 3498            SelectMode::Line(_) => 3,
 3499            SelectMode::All => 4,
 3500        });
 3501        self.begin_selection(position, false, click_count, window, cx);
 3502
 3503        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3504
 3505        let current_selection = match self.selections.select_mode() {
 3506            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3507            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3508        };
 3509
 3510        let mut pending_selection = self
 3511            .selections
 3512            .pending_anchor()
 3513            .cloned()
 3514            .expect("extend_selection not called with pending selection");
 3515
 3516        if pending_selection
 3517            .start
 3518            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3519            == Ordering::Greater
 3520        {
 3521            pending_selection.start = current_selection.start;
 3522        }
 3523        if pending_selection
 3524            .end
 3525            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3526            == Ordering::Less
 3527        {
 3528            pending_selection.end = current_selection.end;
 3529            pending_selection.reversed = true;
 3530        }
 3531
 3532        let mut pending_mode = self.selections.pending_mode().unwrap();
 3533        match &mut pending_mode {
 3534            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3535            _ => {}
 3536        }
 3537
 3538        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3539            SelectionEffects::scroll(Autoscroll::fit())
 3540        } else {
 3541            SelectionEffects::no_scroll()
 3542        };
 3543
 3544        self.change_selections(effects, window, cx, |s| {
 3545            s.set_pending(pending_selection.clone(), pending_mode);
 3546            s.set_is_extending(true);
 3547        });
 3548    }
 3549
 3550    fn begin_selection(
 3551        &mut self,
 3552        position: DisplayPoint,
 3553        add: bool,
 3554        click_count: usize,
 3555        window: &mut Window,
 3556        cx: &mut Context<Self>,
 3557    ) {
 3558        if !self.focus_handle.is_focused(window) {
 3559            self.last_focused_descendant = None;
 3560            window.focus(&self.focus_handle);
 3561        }
 3562
 3563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3564        let buffer = display_map.buffer_snapshot();
 3565        let position = display_map.clip_point(position, Bias::Left);
 3566
 3567        let start;
 3568        let end;
 3569        let mode;
 3570        let mut auto_scroll;
 3571        match click_count {
 3572            1 => {
 3573                start = buffer.anchor_before(position.to_point(&display_map));
 3574                end = start;
 3575                mode = SelectMode::Character;
 3576                auto_scroll = true;
 3577            }
 3578            2 => {
 3579                let position = display_map
 3580                    .clip_point(position, Bias::Left)
 3581                    .to_offset(&display_map, Bias::Left);
 3582                let (range, _) = buffer.surrounding_word(position, None);
 3583                start = buffer.anchor_before(range.start);
 3584                end = buffer.anchor_before(range.end);
 3585                mode = SelectMode::Word(start..end);
 3586                auto_scroll = true;
 3587            }
 3588            3 => {
 3589                let position = display_map
 3590                    .clip_point(position, Bias::Left)
 3591                    .to_point(&display_map);
 3592                let line_start = display_map.prev_line_boundary(position).0;
 3593                let next_line_start = buffer.clip_point(
 3594                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3595                    Bias::Left,
 3596                );
 3597                start = buffer.anchor_before(line_start);
 3598                end = buffer.anchor_before(next_line_start);
 3599                mode = SelectMode::Line(start..end);
 3600                auto_scroll = true;
 3601            }
 3602            _ => {
 3603                start = buffer.anchor_before(0);
 3604                end = buffer.anchor_before(buffer.len());
 3605                mode = SelectMode::All;
 3606                auto_scroll = false;
 3607            }
 3608        }
 3609        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3610
 3611        let point_to_delete: Option<usize> = {
 3612            let selected_points: Vec<Selection<Point>> =
 3613                self.selections.disjoint_in_range(start..end, cx);
 3614
 3615            if !add || click_count > 1 {
 3616                None
 3617            } else if !selected_points.is_empty() {
 3618                Some(selected_points[0].id)
 3619            } else {
 3620                let clicked_point_already_selected =
 3621                    self.selections.disjoint_anchors().iter().find(|selection| {
 3622                        selection.start.to_point(buffer) == start.to_point(buffer)
 3623                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3624                    });
 3625
 3626                clicked_point_already_selected.map(|selection| selection.id)
 3627            }
 3628        };
 3629
 3630        let selections_count = self.selections.count();
 3631        let effects = if auto_scroll {
 3632            SelectionEffects::default()
 3633        } else {
 3634            SelectionEffects::no_scroll()
 3635        };
 3636
 3637        self.change_selections(effects, window, cx, |s| {
 3638            if let Some(point_to_delete) = point_to_delete {
 3639                s.delete(point_to_delete);
 3640
 3641                if selections_count == 1 {
 3642                    s.set_pending_anchor_range(start..end, mode);
 3643                }
 3644            } else {
 3645                if !add {
 3646                    s.clear_disjoint();
 3647                }
 3648
 3649                s.set_pending_anchor_range(start..end, mode);
 3650            }
 3651        });
 3652    }
 3653
 3654    fn begin_columnar_selection(
 3655        &mut self,
 3656        position: DisplayPoint,
 3657        goal_column: u32,
 3658        reset: bool,
 3659        mode: ColumnarMode,
 3660        window: &mut Window,
 3661        cx: &mut Context<Self>,
 3662    ) {
 3663        if !self.focus_handle.is_focused(window) {
 3664            self.last_focused_descendant = None;
 3665            window.focus(&self.focus_handle);
 3666        }
 3667
 3668        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3669
 3670        if reset {
 3671            let pointer_position = display_map
 3672                .buffer_snapshot()
 3673                .anchor_before(position.to_point(&display_map));
 3674
 3675            self.change_selections(
 3676                SelectionEffects::scroll(Autoscroll::newest()),
 3677                window,
 3678                cx,
 3679                |s| {
 3680                    s.clear_disjoint();
 3681                    s.set_pending_anchor_range(
 3682                        pointer_position..pointer_position,
 3683                        SelectMode::Character,
 3684                    );
 3685                },
 3686            );
 3687        };
 3688
 3689        let tail = self.selections.newest::<Point>(cx).tail();
 3690        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3691        self.columnar_selection_state = match mode {
 3692            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3693                selection_tail: selection_anchor,
 3694                display_point: if reset {
 3695                    if position.column() != goal_column {
 3696                        Some(DisplayPoint::new(position.row(), goal_column))
 3697                    } else {
 3698                        None
 3699                    }
 3700                } else {
 3701                    None
 3702                },
 3703            }),
 3704            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3705                selection_tail: selection_anchor,
 3706            }),
 3707        };
 3708
 3709        if !reset {
 3710            self.select_columns(position, goal_column, &display_map, window, cx);
 3711        }
 3712    }
 3713
 3714    fn update_selection(
 3715        &mut self,
 3716        position: DisplayPoint,
 3717        goal_column: u32,
 3718        scroll_delta: gpui::Point<f32>,
 3719        window: &mut Window,
 3720        cx: &mut Context<Self>,
 3721    ) {
 3722        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3723
 3724        if self.columnar_selection_state.is_some() {
 3725            self.select_columns(position, goal_column, &display_map, window, cx);
 3726        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3727            let buffer = display_map.buffer_snapshot();
 3728            let head;
 3729            let tail;
 3730            let mode = self.selections.pending_mode().unwrap();
 3731            match &mode {
 3732                SelectMode::Character => {
 3733                    head = position.to_point(&display_map);
 3734                    tail = pending.tail().to_point(buffer);
 3735                }
 3736                SelectMode::Word(original_range) => {
 3737                    let offset = display_map
 3738                        .clip_point(position, Bias::Left)
 3739                        .to_offset(&display_map, Bias::Left);
 3740                    let original_range = original_range.to_offset(buffer);
 3741
 3742                    let head_offset = if buffer.is_inside_word(offset, None)
 3743                        || original_range.contains(&offset)
 3744                    {
 3745                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3746                        if word_range.start < original_range.start {
 3747                            word_range.start
 3748                        } else {
 3749                            word_range.end
 3750                        }
 3751                    } else {
 3752                        offset
 3753                    };
 3754
 3755                    head = head_offset.to_point(buffer);
 3756                    if head_offset <= original_range.start {
 3757                        tail = original_range.end.to_point(buffer);
 3758                    } else {
 3759                        tail = original_range.start.to_point(buffer);
 3760                    }
 3761                }
 3762                SelectMode::Line(original_range) => {
 3763                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3764
 3765                    let position = display_map
 3766                        .clip_point(position, Bias::Left)
 3767                        .to_point(&display_map);
 3768                    let line_start = display_map.prev_line_boundary(position).0;
 3769                    let next_line_start = buffer.clip_point(
 3770                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3771                        Bias::Left,
 3772                    );
 3773
 3774                    if line_start < original_range.start {
 3775                        head = line_start
 3776                    } else {
 3777                        head = next_line_start
 3778                    }
 3779
 3780                    if head <= original_range.start {
 3781                        tail = original_range.end;
 3782                    } else {
 3783                        tail = original_range.start;
 3784                    }
 3785                }
 3786                SelectMode::All => {
 3787                    return;
 3788                }
 3789            };
 3790
 3791            if head < tail {
 3792                pending.start = buffer.anchor_before(head);
 3793                pending.end = buffer.anchor_before(tail);
 3794                pending.reversed = true;
 3795            } else {
 3796                pending.start = buffer.anchor_before(tail);
 3797                pending.end = buffer.anchor_before(head);
 3798                pending.reversed = false;
 3799            }
 3800
 3801            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3802                s.set_pending(pending.clone(), mode);
 3803            });
 3804        } else {
 3805            log::error!("update_selection dispatched with no pending selection");
 3806            return;
 3807        }
 3808
 3809        self.apply_scroll_delta(scroll_delta, window, cx);
 3810        cx.notify();
 3811    }
 3812
 3813    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3814        self.columnar_selection_state.take();
 3815        if let Some(pending_mode) = self.selections.pending_mode() {
 3816            let selections = self.selections.all::<usize>(cx);
 3817            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3818                s.select(selections);
 3819                s.clear_pending();
 3820                if s.is_extending() {
 3821                    s.set_is_extending(false);
 3822                } else {
 3823                    s.set_select_mode(pending_mode);
 3824                }
 3825            });
 3826        }
 3827    }
 3828
 3829    fn select_columns(
 3830        &mut self,
 3831        head: DisplayPoint,
 3832        goal_column: u32,
 3833        display_map: &DisplaySnapshot,
 3834        window: &mut Window,
 3835        cx: &mut Context<Self>,
 3836    ) {
 3837        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3838            return;
 3839        };
 3840
 3841        let tail = match columnar_state {
 3842            ColumnarSelectionState::FromMouse {
 3843                selection_tail,
 3844                display_point,
 3845            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3846            ColumnarSelectionState::FromSelection { selection_tail } => {
 3847                selection_tail.to_display_point(display_map)
 3848            }
 3849        };
 3850
 3851        let start_row = cmp::min(tail.row(), head.row());
 3852        let end_row = cmp::max(tail.row(), head.row());
 3853        let start_column = cmp::min(tail.column(), goal_column);
 3854        let end_column = cmp::max(tail.column(), goal_column);
 3855        let reversed = start_column < tail.column();
 3856
 3857        let selection_ranges = (start_row.0..=end_row.0)
 3858            .map(DisplayRow)
 3859            .filter_map(|row| {
 3860                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3861                    || start_column <= display_map.line_len(row))
 3862                    && !display_map.is_block_line(row)
 3863                {
 3864                    let start = display_map
 3865                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3866                        .to_point(display_map);
 3867                    let end = display_map
 3868                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3869                        .to_point(display_map);
 3870                    if reversed {
 3871                        Some(end..start)
 3872                    } else {
 3873                        Some(start..end)
 3874                    }
 3875                } else {
 3876                    None
 3877                }
 3878            })
 3879            .collect::<Vec<_>>();
 3880        if selection_ranges.is_empty() {
 3881            return;
 3882        }
 3883
 3884        let ranges = match columnar_state {
 3885            ColumnarSelectionState::FromMouse { .. } => {
 3886                let mut non_empty_ranges = selection_ranges
 3887                    .iter()
 3888                    .filter(|selection_range| selection_range.start != selection_range.end)
 3889                    .peekable();
 3890                if non_empty_ranges.peek().is_some() {
 3891                    non_empty_ranges.cloned().collect()
 3892                } else {
 3893                    selection_ranges
 3894                }
 3895            }
 3896            _ => selection_ranges,
 3897        };
 3898
 3899        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3900            s.select_ranges(ranges);
 3901        });
 3902        cx.notify();
 3903    }
 3904
 3905    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3906        self.selections
 3907            .all_adjusted(cx)
 3908            .iter()
 3909            .any(|selection| !selection.is_empty())
 3910    }
 3911
 3912    pub fn has_pending_nonempty_selection(&self) -> bool {
 3913        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3914            Some(Selection { start, end, .. }) => start != end,
 3915            None => false,
 3916        };
 3917
 3918        pending_nonempty_selection
 3919            || (self.columnar_selection_state.is_some()
 3920                && self.selections.disjoint_anchors().len() > 1)
 3921    }
 3922
 3923    pub fn has_pending_selection(&self) -> bool {
 3924        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3925    }
 3926
 3927    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3928        self.selection_mark_mode = false;
 3929        self.selection_drag_state = SelectionDragState::None;
 3930
 3931        if self.clear_expanded_diff_hunks(cx) {
 3932            cx.notify();
 3933            return;
 3934        }
 3935        if self.dismiss_menus_and_popups(true, window, cx) {
 3936            return;
 3937        }
 3938
 3939        if self.mode.is_full()
 3940            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3941        {
 3942            return;
 3943        }
 3944
 3945        cx.propagate();
 3946    }
 3947
 3948    pub fn dismiss_menus_and_popups(
 3949        &mut self,
 3950        is_user_requested: bool,
 3951        window: &mut Window,
 3952        cx: &mut Context<Self>,
 3953    ) -> bool {
 3954        if self.take_rename(false, window, cx).is_some() {
 3955            return true;
 3956        }
 3957
 3958        if hide_hover(self, cx) {
 3959            return true;
 3960        }
 3961
 3962        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3963            return true;
 3964        }
 3965
 3966        if self.hide_context_menu(window, cx).is_some() {
 3967            return true;
 3968        }
 3969
 3970        if self.mouse_context_menu.take().is_some() {
 3971            return true;
 3972        }
 3973
 3974        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3975            return true;
 3976        }
 3977
 3978        if self.snippet_stack.pop().is_some() {
 3979            return true;
 3980        }
 3981
 3982        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3983            self.dismiss_diagnostics(cx);
 3984            return true;
 3985        }
 3986
 3987        false
 3988    }
 3989
 3990    fn linked_editing_ranges_for(
 3991        &self,
 3992        selection: Range<text::Anchor>,
 3993        cx: &App,
 3994    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3995        if self.linked_edit_ranges.is_empty() {
 3996            return None;
 3997        }
 3998        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3999            selection.end.buffer_id.and_then(|end_buffer_id| {
 4000                if selection.start.buffer_id != Some(end_buffer_id) {
 4001                    return None;
 4002                }
 4003                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4004                let snapshot = buffer.read(cx).snapshot();
 4005                self.linked_edit_ranges
 4006                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4007                    .map(|ranges| (ranges, snapshot, buffer))
 4008            })?;
 4009        use text::ToOffset as TO;
 4010        // find offset from the start of current range to current cursor position
 4011        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4012
 4013        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4014        let start_difference = start_offset - start_byte_offset;
 4015        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4016        let end_difference = end_offset - start_byte_offset;
 4017        // Current range has associated linked ranges.
 4018        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4019        for range in linked_ranges.iter() {
 4020            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4021            let end_offset = start_offset + end_difference;
 4022            let start_offset = start_offset + start_difference;
 4023            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4024                continue;
 4025            }
 4026            if self.selections.disjoint_anchor_ranges().any(|s| {
 4027                if s.start.buffer_id != selection.start.buffer_id
 4028                    || s.end.buffer_id != selection.end.buffer_id
 4029                {
 4030                    return false;
 4031                }
 4032                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4033                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4034            }) {
 4035                continue;
 4036            }
 4037            let start = buffer_snapshot.anchor_after(start_offset);
 4038            let end = buffer_snapshot.anchor_after(end_offset);
 4039            linked_edits
 4040                .entry(buffer.clone())
 4041                .or_default()
 4042                .push(start..end);
 4043        }
 4044        Some(linked_edits)
 4045    }
 4046
 4047    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4048        let text: Arc<str> = text.into();
 4049
 4050        if self.read_only(cx) {
 4051            return;
 4052        }
 4053
 4054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4055
 4056        let selections = self.selections.all_adjusted(cx);
 4057        let mut bracket_inserted = false;
 4058        let mut edits = Vec::new();
 4059        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4060        let mut new_selections = Vec::with_capacity(selections.len());
 4061        let mut new_autoclose_regions = Vec::new();
 4062        let snapshot = self.buffer.read(cx).read(cx);
 4063        let mut clear_linked_edit_ranges = false;
 4064
 4065        for (selection, autoclose_region) in
 4066            self.selections_with_autoclose_regions(selections, &snapshot)
 4067        {
 4068            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4069                // Determine if the inserted text matches the opening or closing
 4070                // bracket of any of this language's bracket pairs.
 4071                let mut bracket_pair = None;
 4072                let mut is_bracket_pair_start = false;
 4073                let mut is_bracket_pair_end = false;
 4074                if !text.is_empty() {
 4075                    let mut bracket_pair_matching_end = None;
 4076                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4077                    //  and they are removing the character that triggered IME popup.
 4078                    for (pair, enabled) in scope.brackets() {
 4079                        if !pair.close && !pair.surround {
 4080                            continue;
 4081                        }
 4082
 4083                        if enabled && pair.start.ends_with(text.as_ref()) {
 4084                            let prefix_len = pair.start.len() - text.len();
 4085                            let preceding_text_matches_prefix = prefix_len == 0
 4086                                || (selection.start.column >= (prefix_len as u32)
 4087                                    && snapshot.contains_str_at(
 4088                                        Point::new(
 4089                                            selection.start.row,
 4090                                            selection.start.column - (prefix_len as u32),
 4091                                        ),
 4092                                        &pair.start[..prefix_len],
 4093                                    ));
 4094                            if preceding_text_matches_prefix {
 4095                                bracket_pair = Some(pair.clone());
 4096                                is_bracket_pair_start = true;
 4097                                break;
 4098                            }
 4099                        }
 4100                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4101                        {
 4102                            // take first bracket pair matching end, but don't break in case a later bracket
 4103                            // pair matches start
 4104                            bracket_pair_matching_end = Some(pair.clone());
 4105                        }
 4106                    }
 4107                    if let Some(end) = bracket_pair_matching_end
 4108                        && bracket_pair.is_none()
 4109                    {
 4110                        bracket_pair = Some(end);
 4111                        is_bracket_pair_end = true;
 4112                    }
 4113                }
 4114
 4115                if let Some(bracket_pair) = bracket_pair {
 4116                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4117                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4118                    let auto_surround =
 4119                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4120                    if selection.is_empty() {
 4121                        if is_bracket_pair_start {
 4122                            // If the inserted text is a suffix of an opening bracket and the
 4123                            // selection is preceded by the rest of the opening bracket, then
 4124                            // insert the closing bracket.
 4125                            let following_text_allows_autoclose = snapshot
 4126                                .chars_at(selection.start)
 4127                                .next()
 4128                                .is_none_or(|c| scope.should_autoclose_before(c));
 4129
 4130                            let preceding_text_allows_autoclose = selection.start.column == 0
 4131                                || snapshot
 4132                                    .reversed_chars_at(selection.start)
 4133                                    .next()
 4134                                    .is_none_or(|c| {
 4135                                        bracket_pair.start != bracket_pair.end
 4136                                            || !snapshot
 4137                                                .char_classifier_at(selection.start)
 4138                                                .is_word(c)
 4139                                    });
 4140
 4141                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4142                                && bracket_pair.start.len() == 1
 4143                            {
 4144                                let target = bracket_pair.start.chars().next().unwrap();
 4145                                let current_line_count = snapshot
 4146                                    .reversed_chars_at(selection.start)
 4147                                    .take_while(|&c| c != '\n')
 4148                                    .filter(|&c| c == target)
 4149                                    .count();
 4150                                current_line_count % 2 == 1
 4151                            } else {
 4152                                false
 4153                            };
 4154
 4155                            if autoclose
 4156                                && bracket_pair.close
 4157                                && following_text_allows_autoclose
 4158                                && preceding_text_allows_autoclose
 4159                                && !is_closing_quote
 4160                            {
 4161                                let anchor = snapshot.anchor_before(selection.end);
 4162                                new_selections.push((selection.map(|_| anchor), text.len()));
 4163                                new_autoclose_regions.push((
 4164                                    anchor,
 4165                                    text.len(),
 4166                                    selection.id,
 4167                                    bracket_pair.clone(),
 4168                                ));
 4169                                edits.push((
 4170                                    selection.range(),
 4171                                    format!("{}{}", text, bracket_pair.end).into(),
 4172                                ));
 4173                                bracket_inserted = true;
 4174                                continue;
 4175                            }
 4176                        }
 4177
 4178                        if let Some(region) = autoclose_region {
 4179                            // If the selection is followed by an auto-inserted closing bracket,
 4180                            // then don't insert that closing bracket again; just move the selection
 4181                            // past the closing bracket.
 4182                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4183                                && text.as_ref() == region.pair.end.as_str()
 4184                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4185                            if should_skip {
 4186                                let anchor = snapshot.anchor_after(selection.end);
 4187                                new_selections
 4188                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4189                                continue;
 4190                            }
 4191                        }
 4192
 4193                        let always_treat_brackets_as_autoclosed = snapshot
 4194                            .language_settings_at(selection.start, cx)
 4195                            .always_treat_brackets_as_autoclosed;
 4196                        if always_treat_brackets_as_autoclosed
 4197                            && is_bracket_pair_end
 4198                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4199                        {
 4200                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4201                            // and the inserted text is a closing bracket and the selection is followed
 4202                            // by the closing bracket then move the selection past the closing bracket.
 4203                            let anchor = snapshot.anchor_after(selection.end);
 4204                            new_selections.push((selection.map(|_| anchor), text.len()));
 4205                            continue;
 4206                        }
 4207                    }
 4208                    // If an opening bracket is 1 character long and is typed while
 4209                    // text is selected, then surround that text with the bracket pair.
 4210                    else if auto_surround
 4211                        && bracket_pair.surround
 4212                        && is_bracket_pair_start
 4213                        && bracket_pair.start.chars().count() == 1
 4214                    {
 4215                        edits.push((selection.start..selection.start, text.clone()));
 4216                        edits.push((
 4217                            selection.end..selection.end,
 4218                            bracket_pair.end.as_str().into(),
 4219                        ));
 4220                        bracket_inserted = true;
 4221                        new_selections.push((
 4222                            Selection {
 4223                                id: selection.id,
 4224                                start: snapshot.anchor_after(selection.start),
 4225                                end: snapshot.anchor_before(selection.end),
 4226                                reversed: selection.reversed,
 4227                                goal: selection.goal,
 4228                            },
 4229                            0,
 4230                        ));
 4231                        continue;
 4232                    }
 4233                }
 4234            }
 4235
 4236            if self.auto_replace_emoji_shortcode
 4237                && selection.is_empty()
 4238                && text.as_ref().ends_with(':')
 4239                && let Some(possible_emoji_short_code) =
 4240                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4241                && !possible_emoji_short_code.is_empty()
 4242                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4243            {
 4244                let emoji_shortcode_start = Point::new(
 4245                    selection.start.row,
 4246                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4247                );
 4248
 4249                // Remove shortcode from buffer
 4250                edits.push((
 4251                    emoji_shortcode_start..selection.start,
 4252                    "".to_string().into(),
 4253                ));
 4254                new_selections.push((
 4255                    Selection {
 4256                        id: selection.id,
 4257                        start: snapshot.anchor_after(emoji_shortcode_start),
 4258                        end: snapshot.anchor_before(selection.start),
 4259                        reversed: selection.reversed,
 4260                        goal: selection.goal,
 4261                    },
 4262                    0,
 4263                ));
 4264
 4265                // Insert emoji
 4266                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4267                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4268                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4269
 4270                continue;
 4271            }
 4272
 4273            // If not handling any auto-close operation, then just replace the selected
 4274            // text with the given input and move the selection to the end of the
 4275            // newly inserted text.
 4276            let anchor = snapshot.anchor_after(selection.end);
 4277            if !self.linked_edit_ranges.is_empty() {
 4278                let start_anchor = snapshot.anchor_before(selection.start);
 4279
 4280                let is_word_char = text.chars().next().is_none_or(|char| {
 4281                    let classifier = snapshot
 4282                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4283                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4284                    classifier.is_word(char)
 4285                });
 4286
 4287                if is_word_char {
 4288                    if let Some(ranges) = self
 4289                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4290                    {
 4291                        for (buffer, edits) in ranges {
 4292                            linked_edits
 4293                                .entry(buffer.clone())
 4294                                .or_default()
 4295                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4296                        }
 4297                    }
 4298                } else {
 4299                    clear_linked_edit_ranges = true;
 4300                }
 4301            }
 4302
 4303            new_selections.push((selection.map(|_| anchor), 0));
 4304            edits.push((selection.start..selection.end, text.clone()));
 4305        }
 4306
 4307        drop(snapshot);
 4308
 4309        self.transact(window, cx, |this, window, cx| {
 4310            if clear_linked_edit_ranges {
 4311                this.linked_edit_ranges.clear();
 4312            }
 4313            let initial_buffer_versions =
 4314                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4315
 4316            this.buffer.update(cx, |buffer, cx| {
 4317                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4318            });
 4319            for (buffer, edits) in linked_edits {
 4320                buffer.update(cx, |buffer, cx| {
 4321                    let snapshot = buffer.snapshot();
 4322                    let edits = edits
 4323                        .into_iter()
 4324                        .map(|(range, text)| {
 4325                            use text::ToPoint as TP;
 4326                            let end_point = TP::to_point(&range.end, &snapshot);
 4327                            let start_point = TP::to_point(&range.start, &snapshot);
 4328                            (start_point..end_point, text)
 4329                        })
 4330                        .sorted_by_key(|(range, _)| range.start);
 4331                    buffer.edit(edits, None, cx);
 4332                })
 4333            }
 4334            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4335            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4336            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4337            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4338                .zip(new_selection_deltas)
 4339                .map(|(selection, delta)| Selection {
 4340                    id: selection.id,
 4341                    start: selection.start + delta,
 4342                    end: selection.end + delta,
 4343                    reversed: selection.reversed,
 4344                    goal: SelectionGoal::None,
 4345                })
 4346                .collect::<Vec<_>>();
 4347
 4348            let mut i = 0;
 4349            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4350                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4351                let start = map.buffer_snapshot().anchor_before(position);
 4352                let end = map.buffer_snapshot().anchor_after(position);
 4353                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4354                    match existing_state
 4355                        .range
 4356                        .start
 4357                        .cmp(&start, map.buffer_snapshot())
 4358                    {
 4359                        Ordering::Less => i += 1,
 4360                        Ordering::Greater => break,
 4361                        Ordering::Equal => {
 4362                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4363                                Ordering::Less => i += 1,
 4364                                Ordering::Equal => break,
 4365                                Ordering::Greater => break,
 4366                            }
 4367                        }
 4368                    }
 4369                }
 4370                this.autoclose_regions.insert(
 4371                    i,
 4372                    AutocloseRegion {
 4373                        selection_id,
 4374                        range: start..end,
 4375                        pair,
 4376                    },
 4377                );
 4378            }
 4379
 4380            let had_active_edit_prediction = this.has_active_edit_prediction();
 4381            this.change_selections(
 4382                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4383                window,
 4384                cx,
 4385                |s| s.select(new_selections),
 4386            );
 4387
 4388            if !bracket_inserted
 4389                && let Some(on_type_format_task) =
 4390                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4391            {
 4392                on_type_format_task.detach_and_log_err(cx);
 4393            }
 4394
 4395            let editor_settings = EditorSettings::get_global(cx);
 4396            if bracket_inserted
 4397                && (editor_settings.auto_signature_help
 4398                    || editor_settings.show_signature_help_after_edits)
 4399            {
 4400                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4401            }
 4402
 4403            let trigger_in_words =
 4404                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4405            if this.hard_wrap.is_some() {
 4406                let latest: Range<Point> = this.selections.newest(cx).range();
 4407                if latest.is_empty()
 4408                    && this
 4409                        .buffer()
 4410                        .read(cx)
 4411                        .snapshot(cx)
 4412                        .line_len(MultiBufferRow(latest.start.row))
 4413                        == latest.start.column
 4414                {
 4415                    this.rewrap_impl(
 4416                        RewrapOptions {
 4417                            override_language_settings: true,
 4418                            preserve_existing_whitespace: true,
 4419                        },
 4420                        cx,
 4421                    )
 4422                }
 4423            }
 4424            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4425            refresh_linked_ranges(this, window, cx);
 4426            this.refresh_edit_prediction(true, false, window, cx);
 4427            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4428        });
 4429    }
 4430
 4431    fn find_possible_emoji_shortcode_at_position(
 4432        snapshot: &MultiBufferSnapshot,
 4433        position: Point,
 4434    ) -> Option<String> {
 4435        let mut chars = Vec::new();
 4436        let mut found_colon = false;
 4437        for char in snapshot.reversed_chars_at(position).take(100) {
 4438            // Found a possible emoji shortcode in the middle of the buffer
 4439            if found_colon {
 4440                if char.is_whitespace() {
 4441                    chars.reverse();
 4442                    return Some(chars.iter().collect());
 4443                }
 4444                // If the previous character is not a whitespace, we are in the middle of a word
 4445                // and we only want to complete the shortcode if the word is made up of other emojis
 4446                let mut containing_word = String::new();
 4447                for ch in snapshot
 4448                    .reversed_chars_at(position)
 4449                    .skip(chars.len() + 1)
 4450                    .take(100)
 4451                {
 4452                    if ch.is_whitespace() {
 4453                        break;
 4454                    }
 4455                    containing_word.push(ch);
 4456                }
 4457                let containing_word = containing_word.chars().rev().collect::<String>();
 4458                if util::word_consists_of_emojis(containing_word.as_str()) {
 4459                    chars.reverse();
 4460                    return Some(chars.iter().collect());
 4461                }
 4462            }
 4463
 4464            if char.is_whitespace() || !char.is_ascii() {
 4465                return None;
 4466            }
 4467            if char == ':' {
 4468                found_colon = true;
 4469            } else {
 4470                chars.push(char);
 4471            }
 4472        }
 4473        // Found a possible emoji shortcode at the beginning of the buffer
 4474        chars.reverse();
 4475        Some(chars.iter().collect())
 4476    }
 4477
 4478    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4480        self.transact(window, cx, |this, window, cx| {
 4481            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4482                let selections = this.selections.all::<usize>(cx);
 4483                let multi_buffer = this.buffer.read(cx);
 4484                let buffer = multi_buffer.snapshot(cx);
 4485                selections
 4486                    .iter()
 4487                    .map(|selection| {
 4488                        let start_point = selection.start.to_point(&buffer);
 4489                        let mut existing_indent =
 4490                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4491                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4492                        let start = selection.start;
 4493                        let end = selection.end;
 4494                        let selection_is_empty = start == end;
 4495                        let language_scope = buffer.language_scope_at(start);
 4496                        let (
 4497                            comment_delimiter,
 4498                            doc_delimiter,
 4499                            insert_extra_newline,
 4500                            indent_on_newline,
 4501                            indent_on_extra_newline,
 4502                        ) = if let Some(language) = &language_scope {
 4503                            let mut insert_extra_newline =
 4504                                insert_extra_newline_brackets(&buffer, start..end, language)
 4505                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4506
 4507                            // Comment extension on newline is allowed only for cursor selections
 4508                            let comment_delimiter = maybe!({
 4509                                if !selection_is_empty {
 4510                                    return None;
 4511                                }
 4512
 4513                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4514                                    return None;
 4515                                }
 4516
 4517                                let delimiters = language.line_comment_prefixes();
 4518                                let max_len_of_delimiter =
 4519                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4520                                let (snapshot, range) =
 4521                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4522
 4523                                let num_of_whitespaces = snapshot
 4524                                    .chars_for_range(range.clone())
 4525                                    .take_while(|c| c.is_whitespace())
 4526                                    .count();
 4527                                let comment_candidate = snapshot
 4528                                    .chars_for_range(range.clone())
 4529                                    .skip(num_of_whitespaces)
 4530                                    .take(max_len_of_delimiter)
 4531                                    .collect::<String>();
 4532                                let (delimiter, trimmed_len) = delimiters
 4533                                    .iter()
 4534                                    .filter_map(|delimiter| {
 4535                                        let prefix = delimiter.trim_end();
 4536                                        if comment_candidate.starts_with(prefix) {
 4537                                            Some((delimiter, prefix.len()))
 4538                                        } else {
 4539                                            None
 4540                                        }
 4541                                    })
 4542                                    .max_by_key(|(_, len)| *len)?;
 4543
 4544                                if let Some(BlockCommentConfig {
 4545                                    start: block_start, ..
 4546                                }) = language.block_comment()
 4547                                {
 4548                                    let block_start_trimmed = block_start.trim_end();
 4549                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4550                                        let line_content = snapshot
 4551                                            .chars_for_range(range)
 4552                                            .skip(num_of_whitespaces)
 4553                                            .take(block_start_trimmed.len())
 4554                                            .collect::<String>();
 4555
 4556                                        if line_content.starts_with(block_start_trimmed) {
 4557                                            return None;
 4558                                        }
 4559                                    }
 4560                                }
 4561
 4562                                let cursor_is_placed_after_comment_marker =
 4563                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4564                                if cursor_is_placed_after_comment_marker {
 4565                                    Some(delimiter.clone())
 4566                                } else {
 4567                                    None
 4568                                }
 4569                            });
 4570
 4571                            let mut indent_on_newline = IndentSize::spaces(0);
 4572                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4573
 4574                            let doc_delimiter = maybe!({
 4575                                if !selection_is_empty {
 4576                                    return None;
 4577                                }
 4578
 4579                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4580                                    return None;
 4581                                }
 4582
 4583                                let BlockCommentConfig {
 4584                                    start: start_tag,
 4585                                    end: end_tag,
 4586                                    prefix: delimiter,
 4587                                    tab_size: len,
 4588                                } = language.documentation_comment()?;
 4589                                let is_within_block_comment = buffer
 4590                                    .language_scope_at(start_point)
 4591                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4592                                if !is_within_block_comment {
 4593                                    return None;
 4594                                }
 4595
 4596                                let (snapshot, range) =
 4597                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4598
 4599                                let num_of_whitespaces = snapshot
 4600                                    .chars_for_range(range.clone())
 4601                                    .take_while(|c| c.is_whitespace())
 4602                                    .count();
 4603
 4604                                // 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.
 4605                                let column = start_point.column;
 4606                                let cursor_is_after_start_tag = {
 4607                                    let start_tag_len = start_tag.len();
 4608                                    let start_tag_line = snapshot
 4609                                        .chars_for_range(range.clone())
 4610                                        .skip(num_of_whitespaces)
 4611                                        .take(start_tag_len)
 4612                                        .collect::<String>();
 4613                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4614                                        num_of_whitespaces + start_tag_len <= column as usize
 4615                                    } else {
 4616                                        false
 4617                                    }
 4618                                };
 4619
 4620                                let cursor_is_after_delimiter = {
 4621                                    let delimiter_trim = delimiter.trim_end();
 4622                                    let delimiter_line = snapshot
 4623                                        .chars_for_range(range.clone())
 4624                                        .skip(num_of_whitespaces)
 4625                                        .take(delimiter_trim.len())
 4626                                        .collect::<String>();
 4627                                    if delimiter_line.starts_with(delimiter_trim) {
 4628                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4629                                    } else {
 4630                                        false
 4631                                    }
 4632                                };
 4633
 4634                                let cursor_is_before_end_tag_if_exists = {
 4635                                    let mut char_position = 0u32;
 4636                                    let mut end_tag_offset = None;
 4637
 4638                                    'outer: for chunk in snapshot.text_for_range(range) {
 4639                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4640                                            let chars_before_match =
 4641                                                chunk[..byte_pos].chars().count() as u32;
 4642                                            end_tag_offset =
 4643                                                Some(char_position + chars_before_match);
 4644                                            break 'outer;
 4645                                        }
 4646                                        char_position += chunk.chars().count() as u32;
 4647                                    }
 4648
 4649                                    if let Some(end_tag_offset) = end_tag_offset {
 4650                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4651                                        if cursor_is_after_start_tag {
 4652                                            if cursor_is_before_end_tag {
 4653                                                insert_extra_newline = true;
 4654                                            }
 4655                                            let cursor_is_at_start_of_end_tag =
 4656                                                column == end_tag_offset;
 4657                                            if cursor_is_at_start_of_end_tag {
 4658                                                indent_on_extra_newline.len = *len;
 4659                                            }
 4660                                        }
 4661                                        cursor_is_before_end_tag
 4662                                    } else {
 4663                                        true
 4664                                    }
 4665                                };
 4666
 4667                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4668                                    && cursor_is_before_end_tag_if_exists
 4669                                {
 4670                                    if cursor_is_after_start_tag {
 4671                                        indent_on_newline.len = *len;
 4672                                    }
 4673                                    Some(delimiter.clone())
 4674                                } else {
 4675                                    None
 4676                                }
 4677                            });
 4678
 4679                            (
 4680                                comment_delimiter,
 4681                                doc_delimiter,
 4682                                insert_extra_newline,
 4683                                indent_on_newline,
 4684                                indent_on_extra_newline,
 4685                            )
 4686                        } else {
 4687                            (
 4688                                None,
 4689                                None,
 4690                                false,
 4691                                IndentSize::default(),
 4692                                IndentSize::default(),
 4693                            )
 4694                        };
 4695
 4696                        let prevent_auto_indent = doc_delimiter.is_some();
 4697                        let delimiter = comment_delimiter.or(doc_delimiter);
 4698
 4699                        let capacity_for_delimiter =
 4700                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4701                        let mut new_text = String::with_capacity(
 4702                            1 + capacity_for_delimiter
 4703                                + existing_indent.len as usize
 4704                                + indent_on_newline.len as usize
 4705                                + indent_on_extra_newline.len as usize,
 4706                        );
 4707                        new_text.push('\n');
 4708                        new_text.extend(existing_indent.chars());
 4709                        new_text.extend(indent_on_newline.chars());
 4710
 4711                        if let Some(delimiter) = &delimiter {
 4712                            new_text.push_str(delimiter);
 4713                        }
 4714
 4715                        if insert_extra_newline {
 4716                            new_text.push('\n');
 4717                            new_text.extend(existing_indent.chars());
 4718                            new_text.extend(indent_on_extra_newline.chars());
 4719                        }
 4720
 4721                        let anchor = buffer.anchor_after(end);
 4722                        let new_selection = selection.map(|_| anchor);
 4723                        (
 4724                            ((start..end, new_text), prevent_auto_indent),
 4725                            (insert_extra_newline, new_selection),
 4726                        )
 4727                    })
 4728                    .unzip()
 4729            };
 4730
 4731            let mut auto_indent_edits = Vec::new();
 4732            let mut edits = Vec::new();
 4733            for (edit, prevent_auto_indent) in edits_with_flags {
 4734                if prevent_auto_indent {
 4735                    edits.push(edit);
 4736                } else {
 4737                    auto_indent_edits.push(edit);
 4738                }
 4739            }
 4740            if !edits.is_empty() {
 4741                this.edit(edits, cx);
 4742            }
 4743            if !auto_indent_edits.is_empty() {
 4744                this.edit_with_autoindent(auto_indent_edits, cx);
 4745            }
 4746
 4747            let buffer = this.buffer.read(cx).snapshot(cx);
 4748            let new_selections = selection_info
 4749                .into_iter()
 4750                .map(|(extra_newline_inserted, new_selection)| {
 4751                    let mut cursor = new_selection.end.to_point(&buffer);
 4752                    if extra_newline_inserted {
 4753                        cursor.row -= 1;
 4754                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4755                    }
 4756                    new_selection.map(|_| cursor)
 4757                })
 4758                .collect();
 4759
 4760            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4761            this.refresh_edit_prediction(true, false, window, cx);
 4762        });
 4763    }
 4764
 4765    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4767
 4768        let buffer = self.buffer.read(cx);
 4769        let snapshot = buffer.snapshot(cx);
 4770
 4771        let mut edits = Vec::new();
 4772        let mut rows = Vec::new();
 4773
 4774        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4775            let cursor = selection.head();
 4776            let row = cursor.row;
 4777
 4778            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4779
 4780            let newline = "\n".to_string();
 4781            edits.push((start_of_line..start_of_line, newline));
 4782
 4783            rows.push(row + rows_inserted as u32);
 4784        }
 4785
 4786        self.transact(window, cx, |editor, window, cx| {
 4787            editor.edit(edits, cx);
 4788
 4789            editor.change_selections(Default::default(), window, cx, |s| {
 4790                let mut index = 0;
 4791                s.move_cursors_with(|map, _, _| {
 4792                    let row = rows[index];
 4793                    index += 1;
 4794
 4795                    let point = Point::new(row, 0);
 4796                    let boundary = map.next_line_boundary(point).1;
 4797                    let clipped = map.clip_point(boundary, Bias::Left);
 4798
 4799                    (clipped, SelectionGoal::None)
 4800                });
 4801            });
 4802
 4803            let mut indent_edits = Vec::new();
 4804            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4805            for row in rows {
 4806                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4807                for (row, indent) in indents {
 4808                    if indent.len == 0 {
 4809                        continue;
 4810                    }
 4811
 4812                    let text = match indent.kind {
 4813                        IndentKind::Space => " ".repeat(indent.len as usize),
 4814                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4815                    };
 4816                    let point = Point::new(row.0, 0);
 4817                    indent_edits.push((point..point, text));
 4818                }
 4819            }
 4820            editor.edit(indent_edits, cx);
 4821        });
 4822    }
 4823
 4824    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4826
 4827        let buffer = self.buffer.read(cx);
 4828        let snapshot = buffer.snapshot(cx);
 4829
 4830        let mut edits = Vec::new();
 4831        let mut rows = Vec::new();
 4832        let mut rows_inserted = 0;
 4833
 4834        for selection in self.selections.all_adjusted(cx) {
 4835            let cursor = selection.head();
 4836            let row = cursor.row;
 4837
 4838            let point = Point::new(row + 1, 0);
 4839            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4840
 4841            let newline = "\n".to_string();
 4842            edits.push((start_of_line..start_of_line, newline));
 4843
 4844            rows_inserted += 1;
 4845            rows.push(row + rows_inserted);
 4846        }
 4847
 4848        self.transact(window, cx, |editor, window, cx| {
 4849            editor.edit(edits, cx);
 4850
 4851            editor.change_selections(Default::default(), window, cx, |s| {
 4852                let mut index = 0;
 4853                s.move_cursors_with(|map, _, _| {
 4854                    let row = rows[index];
 4855                    index += 1;
 4856
 4857                    let point = Point::new(row, 0);
 4858                    let boundary = map.next_line_boundary(point).1;
 4859                    let clipped = map.clip_point(boundary, Bias::Left);
 4860
 4861                    (clipped, SelectionGoal::None)
 4862                });
 4863            });
 4864
 4865            let mut indent_edits = Vec::new();
 4866            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4867            for row in rows {
 4868                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4869                for (row, indent) in indents {
 4870                    if indent.len == 0 {
 4871                        continue;
 4872                    }
 4873
 4874                    let text = match indent.kind {
 4875                        IndentKind::Space => " ".repeat(indent.len as usize),
 4876                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4877                    };
 4878                    let point = Point::new(row.0, 0);
 4879                    indent_edits.push((point..point, text));
 4880                }
 4881            }
 4882            editor.edit(indent_edits, cx);
 4883        });
 4884    }
 4885
 4886    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4887        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4888            original_indent_columns: Vec::new(),
 4889        });
 4890        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4891    }
 4892
 4893    fn insert_with_autoindent_mode(
 4894        &mut self,
 4895        text: &str,
 4896        autoindent_mode: Option<AutoindentMode>,
 4897        window: &mut Window,
 4898        cx: &mut Context<Self>,
 4899    ) {
 4900        if self.read_only(cx) {
 4901            return;
 4902        }
 4903
 4904        let text: Arc<str> = text.into();
 4905        self.transact(window, cx, |this, window, cx| {
 4906            let old_selections = this.selections.all_adjusted(cx);
 4907            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4908                let anchors = {
 4909                    let snapshot = buffer.read(cx);
 4910                    old_selections
 4911                        .iter()
 4912                        .map(|s| {
 4913                            let anchor = snapshot.anchor_after(s.head());
 4914                            s.map(|_| anchor)
 4915                        })
 4916                        .collect::<Vec<_>>()
 4917                };
 4918                buffer.edit(
 4919                    old_selections
 4920                        .iter()
 4921                        .map(|s| (s.start..s.end, text.clone())),
 4922                    autoindent_mode,
 4923                    cx,
 4924                );
 4925                anchors
 4926            });
 4927
 4928            this.change_selections(Default::default(), window, cx, |s| {
 4929                s.select_anchors(selection_anchors);
 4930            });
 4931
 4932            cx.notify();
 4933        });
 4934    }
 4935
 4936    fn trigger_completion_on_input(
 4937        &mut self,
 4938        text: &str,
 4939        trigger_in_words: bool,
 4940        window: &mut Window,
 4941        cx: &mut Context<Self>,
 4942    ) {
 4943        let completions_source = self
 4944            .context_menu
 4945            .borrow()
 4946            .as_ref()
 4947            .and_then(|menu| match menu {
 4948                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4949                CodeContextMenu::CodeActions(_) => None,
 4950            });
 4951
 4952        match completions_source {
 4953            Some(CompletionsMenuSource::Words { .. }) => {
 4954                self.open_or_update_completions_menu(
 4955                    Some(CompletionsMenuSource::Words {
 4956                        ignore_threshold: false,
 4957                    }),
 4958                    None,
 4959                    window,
 4960                    cx,
 4961                );
 4962            }
 4963            Some(CompletionsMenuSource::Normal)
 4964            | Some(CompletionsMenuSource::SnippetChoices)
 4965            | None
 4966                if self.is_completion_trigger(
 4967                    text,
 4968                    trigger_in_words,
 4969                    completions_source.is_some(),
 4970                    cx,
 4971                ) =>
 4972            {
 4973                self.show_completions(
 4974                    &ShowCompletions {
 4975                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4976                    },
 4977                    window,
 4978                    cx,
 4979                )
 4980            }
 4981            _ => {
 4982                self.hide_context_menu(window, cx);
 4983            }
 4984        }
 4985    }
 4986
 4987    fn is_completion_trigger(
 4988        &self,
 4989        text: &str,
 4990        trigger_in_words: bool,
 4991        menu_is_open: bool,
 4992        cx: &mut Context<Self>,
 4993    ) -> bool {
 4994        let position = self.selections.newest_anchor().head();
 4995        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4996            return false;
 4997        };
 4998
 4999        if let Some(completion_provider) = &self.completion_provider {
 5000            completion_provider.is_completion_trigger(
 5001                &buffer,
 5002                position.text_anchor,
 5003                text,
 5004                trigger_in_words,
 5005                menu_is_open,
 5006                cx,
 5007            )
 5008        } else {
 5009            false
 5010        }
 5011    }
 5012
 5013    /// If any empty selections is touching the start of its innermost containing autoclose
 5014    /// region, expand it to select the brackets.
 5015    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5016        let selections = self.selections.all::<usize>(cx);
 5017        let buffer = self.buffer.read(cx).read(cx);
 5018        let new_selections = self
 5019            .selections_with_autoclose_regions(selections, &buffer)
 5020            .map(|(mut selection, region)| {
 5021                if !selection.is_empty() {
 5022                    return selection;
 5023                }
 5024
 5025                if let Some(region) = region {
 5026                    let mut range = region.range.to_offset(&buffer);
 5027                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5028                        range.start -= region.pair.start.len();
 5029                        if buffer.contains_str_at(range.start, &region.pair.start)
 5030                            && buffer.contains_str_at(range.end, &region.pair.end)
 5031                        {
 5032                            range.end += region.pair.end.len();
 5033                            selection.start = range.start;
 5034                            selection.end = range.end;
 5035
 5036                            return selection;
 5037                        }
 5038                    }
 5039                }
 5040
 5041                let always_treat_brackets_as_autoclosed = buffer
 5042                    .language_settings_at(selection.start, cx)
 5043                    .always_treat_brackets_as_autoclosed;
 5044
 5045                if !always_treat_brackets_as_autoclosed {
 5046                    return selection;
 5047                }
 5048
 5049                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5050                    for (pair, enabled) in scope.brackets() {
 5051                        if !enabled || !pair.close {
 5052                            continue;
 5053                        }
 5054
 5055                        if buffer.contains_str_at(selection.start, &pair.end) {
 5056                            let pair_start_len = pair.start.len();
 5057                            if buffer.contains_str_at(
 5058                                selection.start.saturating_sub(pair_start_len),
 5059                                &pair.start,
 5060                            ) {
 5061                                selection.start -= pair_start_len;
 5062                                selection.end += pair.end.len();
 5063
 5064                                return selection;
 5065                            }
 5066                        }
 5067                    }
 5068                }
 5069
 5070                selection
 5071            })
 5072            .collect();
 5073
 5074        drop(buffer);
 5075        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5076            selections.select(new_selections)
 5077        });
 5078    }
 5079
 5080    /// Iterate the given selections, and for each one, find the smallest surrounding
 5081    /// autoclose region. This uses the ordering of the selections and the autoclose
 5082    /// regions to avoid repeated comparisons.
 5083    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5084        &'a self,
 5085        selections: impl IntoIterator<Item = Selection<D>>,
 5086        buffer: &'a MultiBufferSnapshot,
 5087    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5088        let mut i = 0;
 5089        let mut regions = self.autoclose_regions.as_slice();
 5090        selections.into_iter().map(move |selection| {
 5091            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5092
 5093            let mut enclosing = None;
 5094            while let Some(pair_state) = regions.get(i) {
 5095                if pair_state.range.end.to_offset(buffer) < range.start {
 5096                    regions = &regions[i + 1..];
 5097                    i = 0;
 5098                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5099                    break;
 5100                } else {
 5101                    if pair_state.selection_id == selection.id {
 5102                        enclosing = Some(pair_state);
 5103                    }
 5104                    i += 1;
 5105                }
 5106            }
 5107
 5108            (selection, enclosing)
 5109        })
 5110    }
 5111
 5112    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5113    fn invalidate_autoclose_regions(
 5114        &mut self,
 5115        mut selections: &[Selection<Anchor>],
 5116        buffer: &MultiBufferSnapshot,
 5117    ) {
 5118        self.autoclose_regions.retain(|state| {
 5119            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5120                return false;
 5121            }
 5122
 5123            let mut i = 0;
 5124            while let Some(selection) = selections.get(i) {
 5125                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5126                    selections = &selections[1..];
 5127                    continue;
 5128                }
 5129                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5130                    break;
 5131                }
 5132                if selection.id == state.selection_id {
 5133                    return true;
 5134                } else {
 5135                    i += 1;
 5136                }
 5137            }
 5138            false
 5139        });
 5140    }
 5141
 5142    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5143        let offset = position.to_offset(buffer);
 5144        let (word_range, kind) =
 5145            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5146        if offset > word_range.start && kind == Some(CharKind::Word) {
 5147            Some(
 5148                buffer
 5149                    .text_for_range(word_range.start..offset)
 5150                    .collect::<String>(),
 5151            )
 5152        } else {
 5153            None
 5154        }
 5155    }
 5156
 5157    pub fn toggle_inline_values(
 5158        &mut self,
 5159        _: &ToggleInlineValues,
 5160        _: &mut Window,
 5161        cx: &mut Context<Self>,
 5162    ) {
 5163        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5164
 5165        self.refresh_inline_values(cx);
 5166    }
 5167
 5168    pub fn toggle_inlay_hints(
 5169        &mut self,
 5170        _: &ToggleInlayHints,
 5171        _: &mut Window,
 5172        cx: &mut Context<Self>,
 5173    ) {
 5174        self.refresh_inlay_hints(
 5175            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5176            cx,
 5177        );
 5178    }
 5179
 5180    pub fn inlay_hints_enabled(&self) -> bool {
 5181        self.inlay_hint_cache.enabled
 5182    }
 5183
 5184    pub fn inline_values_enabled(&self) -> bool {
 5185        self.inline_value_cache.enabled
 5186    }
 5187
 5188    #[cfg(any(test, feature = "test-support"))]
 5189    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5190        self.display_map
 5191            .read(cx)
 5192            .current_inlays()
 5193            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5194            .cloned()
 5195            .collect()
 5196    }
 5197
 5198    #[cfg(any(test, feature = "test-support"))]
 5199    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5200        self.display_map
 5201            .read(cx)
 5202            .current_inlays()
 5203            .cloned()
 5204            .collect()
 5205    }
 5206
 5207    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5208        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5209            return;
 5210        }
 5211
 5212        let reason_description = reason.description();
 5213        let ignore_debounce = matches!(
 5214            reason,
 5215            InlayHintRefreshReason::SettingsChange(_)
 5216                | InlayHintRefreshReason::Toggle(_)
 5217                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5218                | InlayHintRefreshReason::ModifiersChanged(_)
 5219        );
 5220        let (invalidate_cache, required_languages) = match reason {
 5221            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5222                match self.inlay_hint_cache.modifiers_override(enabled) {
 5223                    Some(enabled) => {
 5224                        if enabled {
 5225                            (InvalidationStrategy::RefreshRequested, None)
 5226                        } else {
 5227                            self.clear_inlay_hints(cx);
 5228                            return;
 5229                        }
 5230                    }
 5231                    None => return,
 5232                }
 5233            }
 5234            InlayHintRefreshReason::Toggle(enabled) => {
 5235                if self.inlay_hint_cache.toggle(enabled) {
 5236                    if enabled {
 5237                        (InvalidationStrategy::RefreshRequested, None)
 5238                    } else {
 5239                        self.clear_inlay_hints(cx);
 5240                        return;
 5241                    }
 5242                } else {
 5243                    return;
 5244                }
 5245            }
 5246            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5247                match self.inlay_hint_cache.update_settings(
 5248                    &self.buffer,
 5249                    new_settings,
 5250                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5251                    cx,
 5252                ) {
 5253                    ControlFlow::Break(Some(InlaySplice {
 5254                        to_remove,
 5255                        to_insert,
 5256                    })) => {
 5257                        self.splice_inlays(&to_remove, to_insert, cx);
 5258                        return;
 5259                    }
 5260                    ControlFlow::Break(None) => return,
 5261                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5262                }
 5263            }
 5264            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5265                if let Some(InlaySplice {
 5266                    to_remove,
 5267                    to_insert,
 5268                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5269                {
 5270                    self.splice_inlays(&to_remove, to_insert, cx);
 5271                }
 5272                self.display_map.update(cx, |display_map, _| {
 5273                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5274                });
 5275                return;
 5276            }
 5277            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5278            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5279                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5280            }
 5281            InlayHintRefreshReason::RefreshRequested => {
 5282                (InvalidationStrategy::RefreshRequested, None)
 5283            }
 5284        };
 5285
 5286        let mut visible_excerpts = self.visible_excerpts(required_languages.as_ref(), cx);
 5287        visible_excerpts.retain(|_, (buffer, _, _)| {
 5288            self.registered_buffers
 5289                .contains_key(&buffer.read(cx).remote_id())
 5290        });
 5291
 5292        if let Some(InlaySplice {
 5293            to_remove,
 5294            to_insert,
 5295        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5296            reason_description,
 5297            visible_excerpts,
 5298            invalidate_cache,
 5299            ignore_debounce,
 5300            cx,
 5301        ) {
 5302            self.splice_inlays(&to_remove, to_insert, cx);
 5303        }
 5304    }
 5305
 5306    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5307        self.splice_inlays(
 5308            &self
 5309                .visible_inlay_hints(cx)
 5310                .map(|inlay| inlay.id)
 5311                .collect::<Vec<_>>(),
 5312            Vec::new(),
 5313            cx,
 5314        );
 5315    }
 5316
 5317    fn visible_inlay_hints<'a>(
 5318        &'a self,
 5319        cx: &'a Context<Editor>,
 5320    ) -> impl Iterator<Item = &'a Inlay> {
 5321        self.display_map
 5322            .read(cx)
 5323            .current_inlays()
 5324            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5325    }
 5326
 5327    pub fn visible_excerpts(
 5328        &self,
 5329        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5330        cx: &mut Context<Editor>,
 5331    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5332        let Some(project) = self.project() else {
 5333            return HashMap::default();
 5334        };
 5335        let project = project.read(cx);
 5336        let multi_buffer = self.buffer().read(cx);
 5337        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5338        let multi_buffer_visible_start = self
 5339            .scroll_manager
 5340            .anchor()
 5341            .anchor
 5342            .to_point(&multi_buffer_snapshot);
 5343        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5344            multi_buffer_visible_start
 5345                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5346            Bias::Left,
 5347        );
 5348        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5349        multi_buffer_snapshot
 5350            .range_to_buffer_ranges(multi_buffer_visible_range)
 5351            .into_iter()
 5352            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5353            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5354                let buffer_file = project::File::from_dyn(buffer.file())?;
 5355                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5356                let worktree_entry = buffer_worktree
 5357                    .read(cx)
 5358                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5359                if worktree_entry.is_ignored {
 5360                    return None;
 5361                }
 5362
 5363                let language = buffer.language()?;
 5364                if let Some(restrict_to_languages) = restrict_to_languages
 5365                    && !restrict_to_languages.contains(language)
 5366                {
 5367                    return None;
 5368                }
 5369                Some((
 5370                    excerpt_id,
 5371                    (
 5372                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5373                        buffer.version().clone(),
 5374                        excerpt_visible_range,
 5375                    ),
 5376                ))
 5377            })
 5378            .collect()
 5379    }
 5380
 5381    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5382        TextLayoutDetails {
 5383            text_system: window.text_system().clone(),
 5384            editor_style: self.style.clone().unwrap(),
 5385            rem_size: window.rem_size(),
 5386            scroll_anchor: self.scroll_manager.anchor(),
 5387            visible_rows: self.visible_line_count(),
 5388            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5389        }
 5390    }
 5391
 5392    pub fn splice_inlays(
 5393        &self,
 5394        to_remove: &[InlayId],
 5395        to_insert: Vec<Inlay>,
 5396        cx: &mut Context<Self>,
 5397    ) {
 5398        self.display_map.update(cx, |display_map, cx| {
 5399            display_map.splice_inlays(to_remove, to_insert, cx)
 5400        });
 5401        cx.notify();
 5402    }
 5403
 5404    fn trigger_on_type_formatting(
 5405        &self,
 5406        input: String,
 5407        window: &mut Window,
 5408        cx: &mut Context<Self>,
 5409    ) -> Option<Task<Result<()>>> {
 5410        if input.len() != 1 {
 5411            return None;
 5412        }
 5413
 5414        let project = self.project()?;
 5415        let position = self.selections.newest_anchor().head();
 5416        let (buffer, buffer_position) = self
 5417            .buffer
 5418            .read(cx)
 5419            .text_anchor_for_position(position, cx)?;
 5420
 5421        let settings = language_settings::language_settings(
 5422            buffer
 5423                .read(cx)
 5424                .language_at(buffer_position)
 5425                .map(|l| l.name()),
 5426            buffer.read(cx).file(),
 5427            cx,
 5428        );
 5429        if !settings.use_on_type_format {
 5430            return None;
 5431        }
 5432
 5433        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5434        // hence we do LSP request & edit on host side only — add formats to host's history.
 5435        let push_to_lsp_host_history = true;
 5436        // If this is not the host, append its history with new edits.
 5437        let push_to_client_history = project.read(cx).is_via_collab();
 5438
 5439        let on_type_formatting = project.update(cx, |project, cx| {
 5440            project.on_type_format(
 5441                buffer.clone(),
 5442                buffer_position,
 5443                input,
 5444                push_to_lsp_host_history,
 5445                cx,
 5446            )
 5447        });
 5448        Some(cx.spawn_in(window, async move |editor, cx| {
 5449            if let Some(transaction) = on_type_formatting.await? {
 5450                if push_to_client_history {
 5451                    buffer
 5452                        .update(cx, |buffer, _| {
 5453                            buffer.push_transaction(transaction, Instant::now());
 5454                            buffer.finalize_last_transaction();
 5455                        })
 5456                        .ok();
 5457                }
 5458                editor.update(cx, |editor, cx| {
 5459                    editor.refresh_document_highlights(cx);
 5460                })?;
 5461            }
 5462            Ok(())
 5463        }))
 5464    }
 5465
 5466    pub fn show_word_completions(
 5467        &mut self,
 5468        _: &ShowWordCompletions,
 5469        window: &mut Window,
 5470        cx: &mut Context<Self>,
 5471    ) {
 5472        self.open_or_update_completions_menu(
 5473            Some(CompletionsMenuSource::Words {
 5474                ignore_threshold: true,
 5475            }),
 5476            None,
 5477            window,
 5478            cx,
 5479        );
 5480    }
 5481
 5482    pub fn show_completions(
 5483        &mut self,
 5484        options: &ShowCompletions,
 5485        window: &mut Window,
 5486        cx: &mut Context<Self>,
 5487    ) {
 5488        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5489    }
 5490
 5491    fn open_or_update_completions_menu(
 5492        &mut self,
 5493        requested_source: Option<CompletionsMenuSource>,
 5494        trigger: Option<&str>,
 5495        window: &mut Window,
 5496        cx: &mut Context<Self>,
 5497    ) {
 5498        if self.pending_rename.is_some() {
 5499            return;
 5500        }
 5501
 5502        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5503
 5504        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5505        // inserted and selected. To handle that case, the start of the selection is used so that
 5506        // the menu starts with all choices.
 5507        let position = self
 5508            .selections
 5509            .newest_anchor()
 5510            .start
 5511            .bias_right(&multibuffer_snapshot);
 5512        if position.diff_base_anchor.is_some() {
 5513            return;
 5514        }
 5515        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5516        let Some(buffer) = buffer_position
 5517            .buffer_id
 5518            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5519        else {
 5520            return;
 5521        };
 5522        let buffer_snapshot = buffer.read(cx).snapshot();
 5523
 5524        let query: Option<Arc<String>> =
 5525            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5526                .map(|query| query.into());
 5527
 5528        drop(multibuffer_snapshot);
 5529
 5530        // Hide the current completions menu when query is empty. Without this, cached
 5531        // completions from before the trigger char may be reused (#32774).
 5532        if query.is_none() {
 5533            let menu_is_open = matches!(
 5534                self.context_menu.borrow().as_ref(),
 5535                Some(CodeContextMenu::Completions(_))
 5536            );
 5537            if menu_is_open {
 5538                self.hide_context_menu(window, cx);
 5539            }
 5540        }
 5541
 5542        let mut ignore_word_threshold = false;
 5543        let provider = match requested_source {
 5544            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5545            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5546                ignore_word_threshold = ignore_threshold;
 5547                None
 5548            }
 5549            Some(CompletionsMenuSource::SnippetChoices) => {
 5550                log::error!("bug: SnippetChoices requested_source is not handled");
 5551                None
 5552            }
 5553        };
 5554
 5555        let sort_completions = provider
 5556            .as_ref()
 5557            .is_some_and(|provider| provider.sort_completions());
 5558
 5559        let filter_completions = provider
 5560            .as_ref()
 5561            .is_none_or(|provider| provider.filter_completions());
 5562
 5563        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5564            if filter_completions {
 5565                menu.filter(query.clone(), provider.clone(), window, cx);
 5566            }
 5567            // When `is_incomplete` is false, no need to re-query completions when the current query
 5568            // is a suffix of the initial query.
 5569            if !menu.is_incomplete {
 5570                // If the new query is a suffix of the old query (typing more characters) and
 5571                // the previous result was complete, the existing completions can be filtered.
 5572                //
 5573                // Note that this is always true for snippet completions.
 5574                let query_matches = match (&menu.initial_query, &query) {
 5575                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5576                    (None, _) => true,
 5577                    _ => false,
 5578                };
 5579                if query_matches {
 5580                    let position_matches = if menu.initial_position == position {
 5581                        true
 5582                    } else {
 5583                        let snapshot = self.buffer.read(cx).read(cx);
 5584                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5585                    };
 5586                    if position_matches {
 5587                        return;
 5588                    }
 5589                }
 5590            }
 5591        };
 5592
 5593        let trigger_kind = match trigger {
 5594            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5595                CompletionTriggerKind::TRIGGER_CHARACTER
 5596            }
 5597            _ => CompletionTriggerKind::INVOKED,
 5598        };
 5599        let completion_context = CompletionContext {
 5600            trigger_character: trigger.and_then(|trigger| {
 5601                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5602                    Some(String::from(trigger))
 5603                } else {
 5604                    None
 5605                }
 5606            }),
 5607            trigger_kind,
 5608        };
 5609
 5610        let Anchor {
 5611            excerpt_id: buffer_excerpt_id,
 5612            text_anchor: buffer_position,
 5613            ..
 5614        } = buffer_position;
 5615
 5616        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5617            buffer_snapshot.surrounding_word(buffer_position, None)
 5618        {
 5619            let word_to_exclude = buffer_snapshot
 5620                .text_for_range(word_range.clone())
 5621                .collect::<String>();
 5622            (
 5623                buffer_snapshot.anchor_before(word_range.start)
 5624                    ..buffer_snapshot.anchor_after(buffer_position),
 5625                Some(word_to_exclude),
 5626            )
 5627        } else {
 5628            (buffer_position..buffer_position, None)
 5629        };
 5630
 5631        let language = buffer_snapshot
 5632            .language_at(buffer_position)
 5633            .map(|language| language.name());
 5634
 5635        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5636            .completions
 5637            .clone();
 5638
 5639        let show_completion_documentation = buffer_snapshot
 5640            .settings_at(buffer_position, cx)
 5641            .show_completion_documentation;
 5642
 5643        // The document can be large, so stay in reasonable bounds when searching for words,
 5644        // otherwise completion pop-up might be slow to appear.
 5645        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5646        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5647        let min_word_search = buffer_snapshot.clip_point(
 5648            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5649            Bias::Left,
 5650        );
 5651        let max_word_search = buffer_snapshot.clip_point(
 5652            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5653            Bias::Right,
 5654        );
 5655        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5656            ..buffer_snapshot.point_to_offset(max_word_search);
 5657
 5658        let skip_digits = query
 5659            .as_ref()
 5660            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5661
 5662        let omit_word_completions = !self.word_completions_enabled
 5663            || (!ignore_word_threshold
 5664                && match &query {
 5665                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5666                    None => completion_settings.words_min_length != 0,
 5667                });
 5668
 5669        let (mut words, provider_responses) = match &provider {
 5670            Some(provider) => {
 5671                let provider_responses = provider.completions(
 5672                    buffer_excerpt_id,
 5673                    &buffer,
 5674                    buffer_position,
 5675                    completion_context,
 5676                    window,
 5677                    cx,
 5678                );
 5679
 5680                let words = match (omit_word_completions, completion_settings.words) {
 5681                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5682                        Task::ready(BTreeMap::default())
 5683                    }
 5684                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5685                        .background_spawn(async move {
 5686                            buffer_snapshot.words_in_range(WordsQuery {
 5687                                fuzzy_contents: None,
 5688                                range: word_search_range,
 5689                                skip_digits,
 5690                            })
 5691                        }),
 5692                };
 5693
 5694                (words, provider_responses)
 5695            }
 5696            None => {
 5697                let words = if omit_word_completions {
 5698                    Task::ready(BTreeMap::default())
 5699                } else {
 5700                    cx.background_spawn(async move {
 5701                        buffer_snapshot.words_in_range(WordsQuery {
 5702                            fuzzy_contents: None,
 5703                            range: word_search_range,
 5704                            skip_digits,
 5705                        })
 5706                    })
 5707                };
 5708                (words, Task::ready(Ok(Vec::new())))
 5709            }
 5710        };
 5711
 5712        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5713
 5714        let id = post_inc(&mut self.next_completion_id);
 5715        let task = cx.spawn_in(window, async move |editor, cx| {
 5716            let Ok(()) = editor.update(cx, |this, _| {
 5717                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5718            }) else {
 5719                return;
 5720            };
 5721
 5722            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5723            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5724            let mut completions = Vec::new();
 5725            let mut is_incomplete = false;
 5726            let mut display_options: Option<CompletionDisplayOptions> = None;
 5727            if let Some(provider_responses) = provider_responses.await.log_err()
 5728                && !provider_responses.is_empty()
 5729            {
 5730                for response in provider_responses {
 5731                    completions.extend(response.completions);
 5732                    is_incomplete = is_incomplete || response.is_incomplete;
 5733                    match display_options.as_mut() {
 5734                        None => {
 5735                            display_options = Some(response.display_options);
 5736                        }
 5737                        Some(options) => options.merge(&response.display_options),
 5738                    }
 5739                }
 5740                if completion_settings.words == WordsCompletionMode::Fallback {
 5741                    words = Task::ready(BTreeMap::default());
 5742                }
 5743            }
 5744            let display_options = display_options.unwrap_or_default();
 5745
 5746            let mut words = words.await;
 5747            if let Some(word_to_exclude) = &word_to_exclude {
 5748                words.remove(word_to_exclude);
 5749            }
 5750            for lsp_completion in &completions {
 5751                words.remove(&lsp_completion.new_text);
 5752            }
 5753            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5754                replace_range: word_replace_range.clone(),
 5755                new_text: word.clone(),
 5756                label: CodeLabel::plain(word, None),
 5757                icon_path: None,
 5758                documentation: None,
 5759                source: CompletionSource::BufferWord {
 5760                    word_range,
 5761                    resolved: false,
 5762                },
 5763                insert_text_mode: Some(InsertTextMode::AS_IS),
 5764                confirm: None,
 5765            }));
 5766
 5767            let menu = if completions.is_empty() {
 5768                None
 5769            } else {
 5770                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5771                    let languages = editor
 5772                        .workspace
 5773                        .as_ref()
 5774                        .and_then(|(workspace, _)| workspace.upgrade())
 5775                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5776                    let menu = CompletionsMenu::new(
 5777                        id,
 5778                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5779                        sort_completions,
 5780                        show_completion_documentation,
 5781                        position,
 5782                        query.clone(),
 5783                        is_incomplete,
 5784                        buffer.clone(),
 5785                        completions.into(),
 5786                        display_options,
 5787                        snippet_sort_order,
 5788                        languages,
 5789                        language,
 5790                        cx,
 5791                    );
 5792
 5793                    let query = if filter_completions { query } else { None };
 5794                    let matches_task = if let Some(query) = query {
 5795                        menu.do_async_filtering(query, cx)
 5796                    } else {
 5797                        Task::ready(menu.unfiltered_matches())
 5798                    };
 5799                    (menu, matches_task)
 5800                }) else {
 5801                    return;
 5802                };
 5803
 5804                let matches = matches_task.await;
 5805
 5806                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5807                    // Newer menu already set, so exit.
 5808                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5809                        editor.context_menu.borrow().as_ref()
 5810                        && prev_menu.id > id
 5811                    {
 5812                        return;
 5813                    };
 5814
 5815                    // Only valid to take prev_menu because it the new menu is immediately set
 5816                    // below, or the menu is hidden.
 5817                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5818                        editor.context_menu.borrow_mut().take()
 5819                    {
 5820                        let position_matches =
 5821                            if prev_menu.initial_position == menu.initial_position {
 5822                                true
 5823                            } else {
 5824                                let snapshot = editor.buffer.read(cx).read(cx);
 5825                                prev_menu.initial_position.to_offset(&snapshot)
 5826                                    == menu.initial_position.to_offset(&snapshot)
 5827                            };
 5828                        if position_matches {
 5829                            // Preserve markdown cache before `set_filter_results` because it will
 5830                            // try to populate the documentation cache.
 5831                            menu.preserve_markdown_cache(prev_menu);
 5832                        }
 5833                    };
 5834
 5835                    menu.set_filter_results(matches, provider, window, cx);
 5836                }) else {
 5837                    return;
 5838                };
 5839
 5840                menu.visible().then_some(menu)
 5841            };
 5842
 5843            editor
 5844                .update_in(cx, |editor, window, cx| {
 5845                    if editor.focus_handle.is_focused(window)
 5846                        && let Some(menu) = menu
 5847                    {
 5848                        *editor.context_menu.borrow_mut() =
 5849                            Some(CodeContextMenu::Completions(menu));
 5850
 5851                        crate::hover_popover::hide_hover(editor, cx);
 5852                        if editor.show_edit_predictions_in_menu() {
 5853                            editor.update_visible_edit_prediction(window, cx);
 5854                        } else {
 5855                            editor.discard_edit_prediction(false, cx);
 5856                        }
 5857
 5858                        cx.notify();
 5859                        return;
 5860                    }
 5861
 5862                    if editor.completion_tasks.len() <= 1 {
 5863                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5864                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5865                        // If it was already hidden and we don't show edit predictions in the menu,
 5866                        // we should also show the edit prediction when available.
 5867                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5868                            editor.update_visible_edit_prediction(window, cx);
 5869                        }
 5870                    }
 5871                })
 5872                .ok();
 5873        });
 5874
 5875        self.completion_tasks.push((id, task));
 5876    }
 5877
 5878    #[cfg(feature = "test-support")]
 5879    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5880        let menu = self.context_menu.borrow();
 5881        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5882            let completions = menu.completions.borrow();
 5883            Some(completions.to_vec())
 5884        } else {
 5885            None
 5886        }
 5887    }
 5888
 5889    pub fn with_completions_menu_matching_id<R>(
 5890        &self,
 5891        id: CompletionId,
 5892        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5893    ) -> R {
 5894        let mut context_menu = self.context_menu.borrow_mut();
 5895        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5896            return f(None);
 5897        };
 5898        if completions_menu.id != id {
 5899            return f(None);
 5900        }
 5901        f(Some(completions_menu))
 5902    }
 5903
 5904    pub fn confirm_completion(
 5905        &mut self,
 5906        action: &ConfirmCompletion,
 5907        window: &mut Window,
 5908        cx: &mut Context<Self>,
 5909    ) -> Option<Task<Result<()>>> {
 5910        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5911        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5912    }
 5913
 5914    pub fn confirm_completion_insert(
 5915        &mut self,
 5916        _: &ConfirmCompletionInsert,
 5917        window: &mut Window,
 5918        cx: &mut Context<Self>,
 5919    ) -> Option<Task<Result<()>>> {
 5920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5921        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5922    }
 5923
 5924    pub fn confirm_completion_replace(
 5925        &mut self,
 5926        _: &ConfirmCompletionReplace,
 5927        window: &mut Window,
 5928        cx: &mut Context<Self>,
 5929    ) -> Option<Task<Result<()>>> {
 5930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5931        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5932    }
 5933
 5934    pub fn compose_completion(
 5935        &mut self,
 5936        action: &ComposeCompletion,
 5937        window: &mut Window,
 5938        cx: &mut Context<Self>,
 5939    ) -> Option<Task<Result<()>>> {
 5940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5941        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5942    }
 5943
 5944    fn do_completion(
 5945        &mut self,
 5946        item_ix: Option<usize>,
 5947        intent: CompletionIntent,
 5948        window: &mut Window,
 5949        cx: &mut Context<Editor>,
 5950    ) -> Option<Task<Result<()>>> {
 5951        use language::ToOffset as _;
 5952
 5953        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5954        else {
 5955            return None;
 5956        };
 5957
 5958        let candidate_id = {
 5959            let entries = completions_menu.entries.borrow();
 5960            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5961            if self.show_edit_predictions_in_menu() {
 5962                self.discard_edit_prediction(true, cx);
 5963            }
 5964            mat.candidate_id
 5965        };
 5966
 5967        let completion = completions_menu
 5968            .completions
 5969            .borrow()
 5970            .get(candidate_id)?
 5971            .clone();
 5972        cx.stop_propagation();
 5973
 5974        let buffer_handle = completions_menu.buffer.clone();
 5975
 5976        let CompletionEdit {
 5977            new_text,
 5978            snippet,
 5979            replace_range,
 5980        } = process_completion_for_edit(
 5981            &completion,
 5982            intent,
 5983            &buffer_handle,
 5984            &completions_menu.initial_position.text_anchor,
 5985            cx,
 5986        );
 5987
 5988        let buffer = buffer_handle.read(cx);
 5989        let snapshot = self.buffer.read(cx).snapshot(cx);
 5990        let newest_anchor = self.selections.newest_anchor();
 5991        let replace_range_multibuffer = {
 5992            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5993            excerpt.map_range_from_buffer(replace_range.clone())
 5994        };
 5995        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5996            return None;
 5997        }
 5998
 5999        let old_text = buffer
 6000            .text_for_range(replace_range.clone())
 6001            .collect::<String>();
 6002        let lookbehind = newest_anchor
 6003            .start
 6004            .text_anchor
 6005            .to_offset(buffer)
 6006            .saturating_sub(replace_range.start);
 6007        let lookahead = replace_range
 6008            .end
 6009            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6010        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6011        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6012
 6013        let selections = self.selections.all::<usize>(cx);
 6014        let mut ranges = Vec::new();
 6015        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6016
 6017        for selection in &selections {
 6018            let range = if selection.id == newest_anchor.id {
 6019                replace_range_multibuffer.clone()
 6020            } else {
 6021                let mut range = selection.range();
 6022
 6023                // if prefix is present, don't duplicate it
 6024                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6025                    range.start = range.start.saturating_sub(lookbehind);
 6026
 6027                    // if suffix is also present, mimic the newest cursor and replace it
 6028                    if selection.id != newest_anchor.id
 6029                        && snapshot.contains_str_at(range.end, suffix)
 6030                    {
 6031                        range.end += lookahead;
 6032                    }
 6033                }
 6034                range
 6035            };
 6036
 6037            ranges.push(range.clone());
 6038
 6039            if !self.linked_edit_ranges.is_empty() {
 6040                let start_anchor = snapshot.anchor_before(range.start);
 6041                let end_anchor = snapshot.anchor_after(range.end);
 6042                if let Some(ranges) = self
 6043                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6044                {
 6045                    for (buffer, edits) in ranges {
 6046                        linked_edits
 6047                            .entry(buffer.clone())
 6048                            .or_default()
 6049                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6050                    }
 6051                }
 6052            }
 6053        }
 6054
 6055        let common_prefix_len = old_text
 6056            .chars()
 6057            .zip(new_text.chars())
 6058            .take_while(|(a, b)| a == b)
 6059            .map(|(a, _)| a.len_utf8())
 6060            .sum::<usize>();
 6061
 6062        cx.emit(EditorEvent::InputHandled {
 6063            utf16_range_to_replace: None,
 6064            text: new_text[common_prefix_len..].into(),
 6065        });
 6066
 6067        self.transact(window, cx, |editor, window, cx| {
 6068            if let Some(mut snippet) = snippet {
 6069                snippet.text = new_text.to_string();
 6070                editor
 6071                    .insert_snippet(&ranges, snippet, window, cx)
 6072                    .log_err();
 6073            } else {
 6074                editor.buffer.update(cx, |multi_buffer, cx| {
 6075                    let auto_indent = match completion.insert_text_mode {
 6076                        Some(InsertTextMode::AS_IS) => None,
 6077                        _ => editor.autoindent_mode.clone(),
 6078                    };
 6079                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6080                    multi_buffer.edit(edits, auto_indent, cx);
 6081                });
 6082            }
 6083            for (buffer, edits) in linked_edits {
 6084                buffer.update(cx, |buffer, cx| {
 6085                    let snapshot = buffer.snapshot();
 6086                    let edits = edits
 6087                        .into_iter()
 6088                        .map(|(range, text)| {
 6089                            use text::ToPoint as TP;
 6090                            let end_point = TP::to_point(&range.end, &snapshot);
 6091                            let start_point = TP::to_point(&range.start, &snapshot);
 6092                            (start_point..end_point, text)
 6093                        })
 6094                        .sorted_by_key(|(range, _)| range.start);
 6095                    buffer.edit(edits, None, cx);
 6096                })
 6097            }
 6098
 6099            editor.refresh_edit_prediction(true, false, window, cx);
 6100        });
 6101        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6102
 6103        let show_new_completions_on_confirm = completion
 6104            .confirm
 6105            .as_ref()
 6106            .is_some_and(|confirm| confirm(intent, window, cx));
 6107        if show_new_completions_on_confirm {
 6108            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6109        }
 6110
 6111        let provider = self.completion_provider.as_ref()?;
 6112        drop(completion);
 6113        let apply_edits = provider.apply_additional_edits_for_completion(
 6114            buffer_handle,
 6115            completions_menu.completions.clone(),
 6116            candidate_id,
 6117            true,
 6118            cx,
 6119        );
 6120
 6121        let editor_settings = EditorSettings::get_global(cx);
 6122        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6123            // After the code completion is finished, users often want to know what signatures are needed.
 6124            // so we should automatically call signature_help
 6125            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6126        }
 6127
 6128        Some(cx.foreground_executor().spawn(async move {
 6129            apply_edits.await?;
 6130            Ok(())
 6131        }))
 6132    }
 6133
 6134    pub fn toggle_code_actions(
 6135        &mut self,
 6136        action: &ToggleCodeActions,
 6137        window: &mut Window,
 6138        cx: &mut Context<Self>,
 6139    ) {
 6140        let quick_launch = action.quick_launch;
 6141        let mut context_menu = self.context_menu.borrow_mut();
 6142        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6143            if code_actions.deployed_from == action.deployed_from {
 6144                // Toggle if we're selecting the same one
 6145                *context_menu = None;
 6146                cx.notify();
 6147                return;
 6148            } else {
 6149                // Otherwise, clear it and start a new one
 6150                *context_menu = None;
 6151                cx.notify();
 6152            }
 6153        }
 6154        drop(context_menu);
 6155        let snapshot = self.snapshot(window, cx);
 6156        let deployed_from = action.deployed_from.clone();
 6157        let action = action.clone();
 6158        self.completion_tasks.clear();
 6159        self.discard_edit_prediction(false, cx);
 6160
 6161        let multibuffer_point = match &action.deployed_from {
 6162            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6163                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6164            }
 6165            _ => self.selections.newest::<Point>(cx).head(),
 6166        };
 6167        let Some((buffer, buffer_row)) = snapshot
 6168            .buffer_snapshot()
 6169            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6170            .and_then(|(buffer_snapshot, range)| {
 6171                self.buffer()
 6172                    .read(cx)
 6173                    .buffer(buffer_snapshot.remote_id())
 6174                    .map(|buffer| (buffer, range.start.row))
 6175            })
 6176        else {
 6177            return;
 6178        };
 6179        let buffer_id = buffer.read(cx).remote_id();
 6180        let tasks = self
 6181            .tasks
 6182            .get(&(buffer_id, buffer_row))
 6183            .map(|t| Arc::new(t.to_owned()));
 6184
 6185        if !self.focus_handle.is_focused(window) {
 6186            return;
 6187        }
 6188        let project = self.project.clone();
 6189
 6190        let code_actions_task = match deployed_from {
 6191            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6192            _ => self.code_actions(buffer_row, window, cx),
 6193        };
 6194
 6195        let runnable_task = match deployed_from {
 6196            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6197            _ => {
 6198                let mut task_context_task = Task::ready(None);
 6199                if let Some(tasks) = &tasks
 6200                    && let Some(project) = project
 6201                {
 6202                    task_context_task =
 6203                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6204                }
 6205
 6206                cx.spawn_in(window, {
 6207                    let buffer = buffer.clone();
 6208                    async move |editor, cx| {
 6209                        let task_context = task_context_task.await;
 6210
 6211                        let resolved_tasks =
 6212                            tasks
 6213                                .zip(task_context.clone())
 6214                                .map(|(tasks, task_context)| ResolvedTasks {
 6215                                    templates: tasks.resolve(&task_context).collect(),
 6216                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6217                                        multibuffer_point.row,
 6218                                        tasks.column,
 6219                                    )),
 6220                                });
 6221                        let debug_scenarios = editor
 6222                            .update(cx, |editor, cx| {
 6223                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6224                            })?
 6225                            .await;
 6226                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6227                    }
 6228                })
 6229            }
 6230        };
 6231
 6232        cx.spawn_in(window, async move |editor, cx| {
 6233            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6234            let code_actions = code_actions_task.await;
 6235            let spawn_straight_away = quick_launch
 6236                && resolved_tasks
 6237                    .as_ref()
 6238                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6239                && code_actions
 6240                    .as_ref()
 6241                    .is_none_or(|actions| actions.is_empty())
 6242                && debug_scenarios.is_empty();
 6243
 6244            editor.update_in(cx, |editor, window, cx| {
 6245                crate::hover_popover::hide_hover(editor, cx);
 6246                let actions = CodeActionContents::new(
 6247                    resolved_tasks,
 6248                    code_actions,
 6249                    debug_scenarios,
 6250                    task_context.unwrap_or_default(),
 6251                );
 6252
 6253                // Don't show the menu if there are no actions available
 6254                if actions.is_empty() {
 6255                    cx.notify();
 6256                    return Task::ready(Ok(()));
 6257                }
 6258
 6259                *editor.context_menu.borrow_mut() =
 6260                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6261                        buffer,
 6262                        actions,
 6263                        selected_item: Default::default(),
 6264                        scroll_handle: UniformListScrollHandle::default(),
 6265                        deployed_from,
 6266                    }));
 6267                cx.notify();
 6268                if spawn_straight_away
 6269                    && let Some(task) = editor.confirm_code_action(
 6270                        &ConfirmCodeAction { item_ix: Some(0) },
 6271                        window,
 6272                        cx,
 6273                    )
 6274                {
 6275                    return task;
 6276                }
 6277
 6278                Task::ready(Ok(()))
 6279            })
 6280        })
 6281        .detach_and_log_err(cx);
 6282    }
 6283
 6284    fn debug_scenarios(
 6285        &mut self,
 6286        resolved_tasks: &Option<ResolvedTasks>,
 6287        buffer: &Entity<Buffer>,
 6288        cx: &mut App,
 6289    ) -> Task<Vec<task::DebugScenario>> {
 6290        maybe!({
 6291            let project = self.project()?;
 6292            let dap_store = project.read(cx).dap_store();
 6293            let mut scenarios = vec![];
 6294            let resolved_tasks = resolved_tasks.as_ref()?;
 6295            let buffer = buffer.read(cx);
 6296            let language = buffer.language()?;
 6297            let file = buffer.file();
 6298            let debug_adapter = language_settings(language.name().into(), file, cx)
 6299                .debuggers
 6300                .first()
 6301                .map(SharedString::from)
 6302                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6303
 6304            dap_store.update(cx, |dap_store, cx| {
 6305                for (_, task) in &resolved_tasks.templates {
 6306                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6307                        task.original_task().clone(),
 6308                        debug_adapter.clone().into(),
 6309                        task.display_label().to_owned().into(),
 6310                        cx,
 6311                    );
 6312                    scenarios.push(maybe_scenario);
 6313                }
 6314            });
 6315            Some(cx.background_spawn(async move {
 6316                futures::future::join_all(scenarios)
 6317                    .await
 6318                    .into_iter()
 6319                    .flatten()
 6320                    .collect::<Vec<_>>()
 6321            }))
 6322        })
 6323        .unwrap_or_else(|| Task::ready(vec![]))
 6324    }
 6325
 6326    fn code_actions(
 6327        &mut self,
 6328        buffer_row: u32,
 6329        window: &mut Window,
 6330        cx: &mut Context<Self>,
 6331    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6332        let mut task = self.code_actions_task.take();
 6333        cx.spawn_in(window, async move |editor, cx| {
 6334            while let Some(prev_task) = task {
 6335                prev_task.await.log_err();
 6336                task = editor
 6337                    .update(cx, |this, _| this.code_actions_task.take())
 6338                    .ok()?;
 6339            }
 6340
 6341            editor
 6342                .update(cx, |editor, cx| {
 6343                    editor
 6344                        .available_code_actions
 6345                        .clone()
 6346                        .and_then(|(location, code_actions)| {
 6347                            let snapshot = location.buffer.read(cx).snapshot();
 6348                            let point_range = location.range.to_point(&snapshot);
 6349                            let point_range = point_range.start.row..=point_range.end.row;
 6350                            if point_range.contains(&buffer_row) {
 6351                                Some(code_actions)
 6352                            } else {
 6353                                None
 6354                            }
 6355                        })
 6356                })
 6357                .ok()
 6358                .flatten()
 6359        })
 6360    }
 6361
 6362    pub fn confirm_code_action(
 6363        &mut self,
 6364        action: &ConfirmCodeAction,
 6365        window: &mut Window,
 6366        cx: &mut Context<Self>,
 6367    ) -> Option<Task<Result<()>>> {
 6368        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6369
 6370        let actions_menu =
 6371            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6372                menu
 6373            } else {
 6374                return None;
 6375            };
 6376
 6377        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6378        let action = actions_menu.actions.get(action_ix)?;
 6379        let title = action.label();
 6380        let buffer = actions_menu.buffer;
 6381        let workspace = self.workspace()?;
 6382
 6383        match action {
 6384            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6385                workspace.update(cx, |workspace, cx| {
 6386                    workspace.schedule_resolved_task(
 6387                        task_source_kind,
 6388                        resolved_task,
 6389                        false,
 6390                        window,
 6391                        cx,
 6392                    );
 6393
 6394                    Some(Task::ready(Ok(())))
 6395                })
 6396            }
 6397            CodeActionsItem::CodeAction {
 6398                excerpt_id,
 6399                action,
 6400                provider,
 6401            } => {
 6402                let apply_code_action =
 6403                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6404                let workspace = workspace.downgrade();
 6405                Some(cx.spawn_in(window, async move |editor, cx| {
 6406                    let project_transaction = apply_code_action.await?;
 6407                    Self::open_project_transaction(
 6408                        &editor,
 6409                        workspace,
 6410                        project_transaction,
 6411                        title,
 6412                        cx,
 6413                    )
 6414                    .await
 6415                }))
 6416            }
 6417            CodeActionsItem::DebugScenario(scenario) => {
 6418                let context = actions_menu.actions.context;
 6419
 6420                workspace.update(cx, |workspace, cx| {
 6421                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6422                    workspace.start_debug_session(
 6423                        scenario,
 6424                        context,
 6425                        Some(buffer),
 6426                        None,
 6427                        window,
 6428                        cx,
 6429                    );
 6430                });
 6431                Some(Task::ready(Ok(())))
 6432            }
 6433        }
 6434    }
 6435
 6436    pub async fn open_project_transaction(
 6437        editor: &WeakEntity<Editor>,
 6438        workspace: WeakEntity<Workspace>,
 6439        transaction: ProjectTransaction,
 6440        title: String,
 6441        cx: &mut AsyncWindowContext,
 6442    ) -> Result<()> {
 6443        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6444        cx.update(|_, cx| {
 6445            entries.sort_unstable_by_key(|(buffer, _)| {
 6446                buffer.read(cx).file().map(|f| f.path().clone())
 6447            });
 6448        })?;
 6449        if entries.is_empty() {
 6450            return Ok(());
 6451        }
 6452
 6453        // If the project transaction's edits are all contained within this editor, then
 6454        // avoid opening a new editor to display them.
 6455
 6456        if let [(buffer, transaction)] = &*entries {
 6457            let excerpt = editor.update(cx, |editor, cx| {
 6458                editor
 6459                    .buffer()
 6460                    .read(cx)
 6461                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6462            })?;
 6463            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6464                && excerpted_buffer == *buffer
 6465            {
 6466                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6467                    let excerpt_range = excerpt_range.to_offset(buffer);
 6468                    buffer
 6469                        .edited_ranges_for_transaction::<usize>(transaction)
 6470                        .all(|range| {
 6471                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6472                        })
 6473                })?;
 6474
 6475                if all_edits_within_excerpt {
 6476                    return Ok(());
 6477                }
 6478            }
 6479        }
 6480
 6481        let mut ranges_to_highlight = Vec::new();
 6482        let excerpt_buffer = cx.new(|cx| {
 6483            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6484            for (buffer_handle, transaction) in &entries {
 6485                let edited_ranges = buffer_handle
 6486                    .read(cx)
 6487                    .edited_ranges_for_transaction::<Point>(transaction)
 6488                    .collect::<Vec<_>>();
 6489                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6490                    PathKey::for_buffer(buffer_handle, cx),
 6491                    buffer_handle.clone(),
 6492                    edited_ranges,
 6493                    multibuffer_context_lines(cx),
 6494                    cx,
 6495                );
 6496
 6497                ranges_to_highlight.extend(ranges);
 6498            }
 6499            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6500            multibuffer
 6501        })?;
 6502
 6503        workspace.update_in(cx, |workspace, window, cx| {
 6504            let project = workspace.project().clone();
 6505            let editor =
 6506                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6507            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6508            editor.update(cx, |editor, cx| {
 6509                editor.highlight_background::<Self>(
 6510                    &ranges_to_highlight,
 6511                    |theme| theme.colors().editor_highlighted_line_background,
 6512                    cx,
 6513                );
 6514            });
 6515        })?;
 6516
 6517        Ok(())
 6518    }
 6519
 6520    pub fn clear_code_action_providers(&mut self) {
 6521        self.code_action_providers.clear();
 6522        self.available_code_actions.take();
 6523    }
 6524
 6525    pub fn add_code_action_provider(
 6526        &mut self,
 6527        provider: Rc<dyn CodeActionProvider>,
 6528        window: &mut Window,
 6529        cx: &mut Context<Self>,
 6530    ) {
 6531        if self
 6532            .code_action_providers
 6533            .iter()
 6534            .any(|existing_provider| existing_provider.id() == provider.id())
 6535        {
 6536            return;
 6537        }
 6538
 6539        self.code_action_providers.push(provider);
 6540        self.refresh_code_actions(window, cx);
 6541    }
 6542
 6543    pub fn remove_code_action_provider(
 6544        &mut self,
 6545        id: Arc<str>,
 6546        window: &mut Window,
 6547        cx: &mut Context<Self>,
 6548    ) {
 6549        self.code_action_providers
 6550            .retain(|provider| provider.id() != id);
 6551        self.refresh_code_actions(window, cx);
 6552    }
 6553
 6554    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6555        !self.code_action_providers.is_empty()
 6556            && EditorSettings::get_global(cx).toolbar.code_actions
 6557    }
 6558
 6559    pub fn has_available_code_actions(&self) -> bool {
 6560        self.available_code_actions
 6561            .as_ref()
 6562            .is_some_and(|(_, actions)| !actions.is_empty())
 6563    }
 6564
 6565    fn render_inline_code_actions(
 6566        &self,
 6567        icon_size: ui::IconSize,
 6568        display_row: DisplayRow,
 6569        is_active: bool,
 6570        cx: &mut Context<Self>,
 6571    ) -> AnyElement {
 6572        let show_tooltip = !self.context_menu_visible();
 6573        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6574            .icon_size(icon_size)
 6575            .shape(ui::IconButtonShape::Square)
 6576            .icon_color(ui::Color::Hidden)
 6577            .toggle_state(is_active)
 6578            .when(show_tooltip, |this| {
 6579                this.tooltip({
 6580                    let focus_handle = self.focus_handle.clone();
 6581                    move |window, cx| {
 6582                        Tooltip::for_action_in(
 6583                            "Toggle Code Actions",
 6584                            &ToggleCodeActions {
 6585                                deployed_from: None,
 6586                                quick_launch: false,
 6587                            },
 6588                            &focus_handle,
 6589                            window,
 6590                            cx,
 6591                        )
 6592                    }
 6593                })
 6594            })
 6595            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6596                window.focus(&editor.focus_handle(cx));
 6597                editor.toggle_code_actions(
 6598                    &crate::actions::ToggleCodeActions {
 6599                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6600                            display_row,
 6601                        )),
 6602                        quick_launch: false,
 6603                    },
 6604                    window,
 6605                    cx,
 6606                );
 6607            }))
 6608            .into_any_element()
 6609    }
 6610
 6611    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6612        &self.context_menu
 6613    }
 6614
 6615    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6616        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6617            cx.background_executor()
 6618                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6619                .await;
 6620
 6621            let (start_buffer, start, _, end, newest_selection) = this
 6622                .update(cx, |this, cx| {
 6623                    let newest_selection = this.selections.newest_anchor().clone();
 6624                    if newest_selection.head().diff_base_anchor.is_some() {
 6625                        return None;
 6626                    }
 6627                    let newest_selection_adjusted = this.selections.newest_adjusted(cx);
 6628                    let buffer = this.buffer.read(cx);
 6629
 6630                    let (start_buffer, start) =
 6631                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6632                    let (end_buffer, end) =
 6633                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6634
 6635                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6636                })?
 6637                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6638                .context(
 6639                    "Expected selection to lie in a single buffer when refreshing code actions",
 6640                )?;
 6641            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6642                let providers = this.code_action_providers.clone();
 6643                let tasks = this
 6644                    .code_action_providers
 6645                    .iter()
 6646                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6647                    .collect::<Vec<_>>();
 6648                (providers, tasks)
 6649            })?;
 6650
 6651            let mut actions = Vec::new();
 6652            for (provider, provider_actions) in
 6653                providers.into_iter().zip(future::join_all(tasks).await)
 6654            {
 6655                if let Some(provider_actions) = provider_actions.log_err() {
 6656                    actions.extend(provider_actions.into_iter().map(|action| {
 6657                        AvailableCodeAction {
 6658                            excerpt_id: newest_selection.start.excerpt_id,
 6659                            action,
 6660                            provider: provider.clone(),
 6661                        }
 6662                    }));
 6663                }
 6664            }
 6665
 6666            this.update(cx, |this, cx| {
 6667                this.available_code_actions = if actions.is_empty() {
 6668                    None
 6669                } else {
 6670                    Some((
 6671                        Location {
 6672                            buffer: start_buffer,
 6673                            range: start..end,
 6674                        },
 6675                        actions.into(),
 6676                    ))
 6677                };
 6678                cx.notify();
 6679            })
 6680        }));
 6681    }
 6682
 6683    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6684        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6685            self.show_git_blame_inline = false;
 6686
 6687            self.show_git_blame_inline_delay_task =
 6688                Some(cx.spawn_in(window, async move |this, cx| {
 6689                    cx.background_executor().timer(delay).await;
 6690
 6691                    this.update(cx, |this, cx| {
 6692                        this.show_git_blame_inline = true;
 6693                        cx.notify();
 6694                    })
 6695                    .log_err();
 6696                }));
 6697        }
 6698    }
 6699
 6700    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6701        let snapshot = self.snapshot(window, cx);
 6702        let cursor = self.selections.newest::<Point>(cx).head();
 6703        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6704        else {
 6705            return;
 6706        };
 6707
 6708        let Some(blame) = self.blame.as_ref() else {
 6709            return;
 6710        };
 6711
 6712        let row_info = RowInfo {
 6713            buffer_id: Some(buffer.remote_id()),
 6714            buffer_row: Some(point.row),
 6715            ..Default::default()
 6716        };
 6717        let Some((buffer, blame_entry)) = blame
 6718            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6719            .flatten()
 6720        else {
 6721            return;
 6722        };
 6723
 6724        let anchor = self.selections.newest_anchor().head();
 6725        let position = self.to_pixel_point(anchor, &snapshot, window);
 6726        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6727            self.show_blame_popover(
 6728                buffer,
 6729                &blame_entry,
 6730                position + last_bounds.origin,
 6731                true,
 6732                cx,
 6733            );
 6734        };
 6735    }
 6736
 6737    fn show_blame_popover(
 6738        &mut self,
 6739        buffer: BufferId,
 6740        blame_entry: &BlameEntry,
 6741        position: gpui::Point<Pixels>,
 6742        ignore_timeout: bool,
 6743        cx: &mut Context<Self>,
 6744    ) {
 6745        if let Some(state) = &mut self.inline_blame_popover {
 6746            state.hide_task.take();
 6747        } else {
 6748            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6749            let blame_entry = blame_entry.clone();
 6750            let show_task = cx.spawn(async move |editor, cx| {
 6751                if !ignore_timeout {
 6752                    cx.background_executor()
 6753                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6754                        .await;
 6755                }
 6756                editor
 6757                    .update(cx, |editor, cx| {
 6758                        editor.inline_blame_popover_show_task.take();
 6759                        let Some(blame) = editor.blame.as_ref() else {
 6760                            return;
 6761                        };
 6762                        let blame = blame.read(cx);
 6763                        let details = blame.details_for_entry(buffer, &blame_entry);
 6764                        let markdown = cx.new(|cx| {
 6765                            Markdown::new(
 6766                                details
 6767                                    .as_ref()
 6768                                    .map(|message| message.message.clone())
 6769                                    .unwrap_or_default(),
 6770                                None,
 6771                                None,
 6772                                cx,
 6773                            )
 6774                        });
 6775                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6776                            position,
 6777                            hide_task: None,
 6778                            popover_bounds: None,
 6779                            popover_state: InlineBlamePopoverState {
 6780                                scroll_handle: ScrollHandle::new(),
 6781                                commit_message: details,
 6782                                markdown,
 6783                            },
 6784                            keyboard_grace: ignore_timeout,
 6785                        });
 6786                        cx.notify();
 6787                    })
 6788                    .ok();
 6789            });
 6790            self.inline_blame_popover_show_task = Some(show_task);
 6791        }
 6792    }
 6793
 6794    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6795        self.inline_blame_popover_show_task.take();
 6796        if let Some(state) = &mut self.inline_blame_popover {
 6797            let hide_task = cx.spawn(async move |editor, cx| {
 6798                cx.background_executor()
 6799                    .timer(std::time::Duration::from_millis(100))
 6800                    .await;
 6801                editor
 6802                    .update(cx, |editor, cx| {
 6803                        editor.inline_blame_popover.take();
 6804                        cx.notify();
 6805                    })
 6806                    .ok();
 6807            });
 6808            state.hide_task = Some(hide_task);
 6809        }
 6810    }
 6811
 6812    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6813        if self.pending_rename.is_some() {
 6814            return None;
 6815        }
 6816
 6817        let provider = self.semantics_provider.clone()?;
 6818        let buffer = self.buffer.read(cx);
 6819        let newest_selection = self.selections.newest_anchor().clone();
 6820        let cursor_position = newest_selection.head();
 6821        let (cursor_buffer, cursor_buffer_position) =
 6822            buffer.text_anchor_for_position(cursor_position, cx)?;
 6823        let (tail_buffer, tail_buffer_position) =
 6824            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6825        if cursor_buffer != tail_buffer {
 6826            return None;
 6827        }
 6828
 6829        let snapshot = cursor_buffer.read(cx).snapshot();
 6830        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6831        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6832        if start_word_range != end_word_range {
 6833            self.document_highlights_task.take();
 6834            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6835            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6836            return None;
 6837        }
 6838
 6839        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6840        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6841            cx.background_executor()
 6842                .timer(Duration::from_millis(debounce))
 6843                .await;
 6844
 6845            let highlights = if let Some(highlights) = cx
 6846                .update(|cx| {
 6847                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6848                })
 6849                .ok()
 6850                .flatten()
 6851            {
 6852                highlights.await.log_err()
 6853            } else {
 6854                None
 6855            };
 6856
 6857            if let Some(highlights) = highlights {
 6858                this.update(cx, |this, cx| {
 6859                    if this.pending_rename.is_some() {
 6860                        return;
 6861                    }
 6862
 6863                    let buffer = this.buffer.read(cx);
 6864                    if buffer
 6865                        .text_anchor_for_position(cursor_position, cx)
 6866                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6867                    {
 6868                        return;
 6869                    }
 6870
 6871                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6872                    let mut write_ranges = Vec::new();
 6873                    let mut read_ranges = Vec::new();
 6874                    for highlight in highlights {
 6875                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6876                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6877                        {
 6878                            let start = highlight
 6879                                .range
 6880                                .start
 6881                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6882                            let end = highlight
 6883                                .range
 6884                                .end
 6885                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6886                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6887                                continue;
 6888                            }
 6889
 6890                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6891                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6892                                write_ranges.push(range);
 6893                            } else {
 6894                                read_ranges.push(range);
 6895                            }
 6896                        }
 6897                    }
 6898
 6899                    this.highlight_background::<DocumentHighlightRead>(
 6900                        &read_ranges,
 6901                        |theme| theme.colors().editor_document_highlight_read_background,
 6902                        cx,
 6903                    );
 6904                    this.highlight_background::<DocumentHighlightWrite>(
 6905                        &write_ranges,
 6906                        |theme| theme.colors().editor_document_highlight_write_background,
 6907                        cx,
 6908                    );
 6909                    cx.notify();
 6910                })
 6911                .log_err();
 6912            }
 6913        }));
 6914        None
 6915    }
 6916
 6917    fn prepare_highlight_query_from_selection(
 6918        &mut self,
 6919        cx: &mut Context<Editor>,
 6920    ) -> Option<(String, Range<Anchor>)> {
 6921        if matches!(self.mode, EditorMode::SingleLine) {
 6922            return None;
 6923        }
 6924        if !EditorSettings::get_global(cx).selection_highlight {
 6925            return None;
 6926        }
 6927        if self.selections.count() != 1 || self.selections.line_mode() {
 6928            return None;
 6929        }
 6930        let selection = self.selections.newest_anchor();
 6931        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6932        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6933            ..selection.end.to_point(&multi_buffer_snapshot);
 6934        // If the selection spans multiple rows OR it is empty
 6935        if selection_point_range.start.row != selection_point_range.end.row
 6936            || selection_point_range.start.column == selection_point_range.end.column
 6937        {
 6938            return None;
 6939        }
 6940
 6941        let query = multi_buffer_snapshot
 6942            .text_for_range(selection.range())
 6943            .collect::<String>();
 6944        if query.trim().is_empty() {
 6945            return None;
 6946        }
 6947        Some((query, selection.range()))
 6948    }
 6949
 6950    fn update_selection_occurrence_highlights(
 6951        &mut self,
 6952        query_text: String,
 6953        query_range: Range<Anchor>,
 6954        multi_buffer_range_to_query: Range<Point>,
 6955        use_debounce: bool,
 6956        window: &mut Window,
 6957        cx: &mut Context<Editor>,
 6958    ) -> Task<()> {
 6959        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6960        cx.spawn_in(window, async move |editor, cx| {
 6961            if use_debounce {
 6962                cx.background_executor()
 6963                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6964                    .await;
 6965            }
 6966            let match_task = cx.background_spawn(async move {
 6967                let buffer_ranges = multi_buffer_snapshot
 6968                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6969                    .into_iter()
 6970                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6971                let mut match_ranges = Vec::new();
 6972                let Ok(regex) = project::search::SearchQuery::text(
 6973                    query_text.clone(),
 6974                    false,
 6975                    false,
 6976                    false,
 6977                    Default::default(),
 6978                    Default::default(),
 6979                    false,
 6980                    None,
 6981                ) else {
 6982                    return Vec::default();
 6983                };
 6984                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6985                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6986                    match_ranges.extend(
 6987                        regex
 6988                            .search(buffer_snapshot, Some(search_range.clone()))
 6989                            .await
 6990                            .into_iter()
 6991                            .filter_map(|match_range| {
 6992                                let match_start = buffer_snapshot
 6993                                    .anchor_after(search_range.start + match_range.start);
 6994                                let match_end = buffer_snapshot
 6995                                    .anchor_before(search_range.start + match_range.end);
 6996                                let match_anchor_range = Anchor::range_in_buffer(
 6997                                    excerpt_id,
 6998                                    buffer_snapshot.remote_id(),
 6999                                    match_start..match_end,
 7000                                );
 7001                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7002                            }),
 7003                    );
 7004                }
 7005                match_ranges
 7006            });
 7007            let match_ranges = match_task.await;
 7008            editor
 7009                .update_in(cx, |editor, _, cx| {
 7010                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7011                    if !match_ranges.is_empty() {
 7012                        editor.highlight_background::<SelectedTextHighlight>(
 7013                            &match_ranges,
 7014                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7015                            cx,
 7016                        )
 7017                    }
 7018                })
 7019                .log_err();
 7020        })
 7021    }
 7022
 7023    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7024        struct NewlineFold;
 7025        let type_id = std::any::TypeId::of::<NewlineFold>();
 7026        if !self.mode.is_single_line() {
 7027            return;
 7028        }
 7029        let snapshot = self.snapshot(window, cx);
 7030        if snapshot.buffer_snapshot().max_point().row == 0 {
 7031            return;
 7032        }
 7033        let task = cx.background_spawn(async move {
 7034            let new_newlines = snapshot
 7035                .buffer_chars_at(0)
 7036                .filter_map(|(c, i)| {
 7037                    if c == '\n' {
 7038                        Some(
 7039                            snapshot.buffer_snapshot().anchor_after(i)
 7040                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7041                        )
 7042                    } else {
 7043                        None
 7044                    }
 7045                })
 7046                .collect::<Vec<_>>();
 7047            let existing_newlines = snapshot
 7048                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7049                .filter_map(|fold| {
 7050                    if fold.placeholder.type_tag == Some(type_id) {
 7051                        Some(fold.range.start..fold.range.end)
 7052                    } else {
 7053                        None
 7054                    }
 7055                })
 7056                .collect::<Vec<_>>();
 7057
 7058            (new_newlines, existing_newlines)
 7059        });
 7060        self.folding_newlines = cx.spawn(async move |this, cx| {
 7061            let (new_newlines, existing_newlines) = task.await;
 7062            if new_newlines == existing_newlines {
 7063                return;
 7064            }
 7065            let placeholder = FoldPlaceholder {
 7066                render: Arc::new(move |_, _, cx| {
 7067                    div()
 7068                        .bg(cx.theme().status().hint_background)
 7069                        .border_b_1()
 7070                        .size_full()
 7071                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7072                        .border_color(cx.theme().status().hint)
 7073                        .child("\\n")
 7074                        .into_any()
 7075                }),
 7076                constrain_width: false,
 7077                merge_adjacent: false,
 7078                type_tag: Some(type_id),
 7079            };
 7080            let creases = new_newlines
 7081                .into_iter()
 7082                .map(|range| Crease::simple(range, placeholder.clone()))
 7083                .collect();
 7084            this.update(cx, |this, cx| {
 7085                this.display_map.update(cx, |display_map, cx| {
 7086                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7087                    display_map.fold(creases, cx);
 7088                });
 7089            })
 7090            .ok();
 7091        });
 7092    }
 7093
 7094    fn refresh_selected_text_highlights(
 7095        &mut self,
 7096        on_buffer_edit: bool,
 7097        window: &mut Window,
 7098        cx: &mut Context<Editor>,
 7099    ) {
 7100        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7101        else {
 7102            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7103            self.quick_selection_highlight_task.take();
 7104            self.debounced_selection_highlight_task.take();
 7105            return;
 7106        };
 7107        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7108        if on_buffer_edit
 7109            || self
 7110                .quick_selection_highlight_task
 7111                .as_ref()
 7112                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7113        {
 7114            let multi_buffer_visible_start = self
 7115                .scroll_manager
 7116                .anchor()
 7117                .anchor
 7118                .to_point(&multi_buffer_snapshot);
 7119            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7120                multi_buffer_visible_start
 7121                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7122                Bias::Left,
 7123            );
 7124            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7125            self.quick_selection_highlight_task = Some((
 7126                query_range.clone(),
 7127                self.update_selection_occurrence_highlights(
 7128                    query_text.clone(),
 7129                    query_range.clone(),
 7130                    multi_buffer_visible_range,
 7131                    false,
 7132                    window,
 7133                    cx,
 7134                ),
 7135            ));
 7136        }
 7137        if on_buffer_edit
 7138            || self
 7139                .debounced_selection_highlight_task
 7140                .as_ref()
 7141                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7142        {
 7143            let multi_buffer_start = multi_buffer_snapshot
 7144                .anchor_before(0)
 7145                .to_point(&multi_buffer_snapshot);
 7146            let multi_buffer_end = multi_buffer_snapshot
 7147                .anchor_after(multi_buffer_snapshot.len())
 7148                .to_point(&multi_buffer_snapshot);
 7149            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7150            self.debounced_selection_highlight_task = Some((
 7151                query_range.clone(),
 7152                self.update_selection_occurrence_highlights(
 7153                    query_text,
 7154                    query_range,
 7155                    multi_buffer_full_range,
 7156                    true,
 7157                    window,
 7158                    cx,
 7159                ),
 7160            ));
 7161        }
 7162    }
 7163
 7164    pub fn refresh_edit_prediction(
 7165        &mut self,
 7166        debounce: bool,
 7167        user_requested: bool,
 7168        window: &mut Window,
 7169        cx: &mut Context<Self>,
 7170    ) -> Option<()> {
 7171        if DisableAiSettings::get_global(cx).disable_ai {
 7172            return None;
 7173        }
 7174
 7175        let provider = self.edit_prediction_provider()?;
 7176        let cursor = self.selections.newest_anchor().head();
 7177        let (buffer, cursor_buffer_position) =
 7178            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7179
 7180        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7181            self.discard_edit_prediction(false, cx);
 7182            return None;
 7183        }
 7184
 7185        self.update_visible_edit_prediction(window, cx);
 7186
 7187        if !user_requested
 7188            && (!self.should_show_edit_predictions()
 7189                || !self.is_focused(window)
 7190                || buffer.read(cx).is_empty())
 7191        {
 7192            self.discard_edit_prediction(false, cx);
 7193            return None;
 7194        }
 7195
 7196        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7197        Some(())
 7198    }
 7199
 7200    fn show_edit_predictions_in_menu(&self) -> bool {
 7201        match self.edit_prediction_settings {
 7202            EditPredictionSettings::Disabled => false,
 7203            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7204        }
 7205    }
 7206
 7207    pub fn edit_predictions_enabled(&self) -> bool {
 7208        match self.edit_prediction_settings {
 7209            EditPredictionSettings::Disabled => false,
 7210            EditPredictionSettings::Enabled { .. } => true,
 7211        }
 7212    }
 7213
 7214    fn edit_prediction_requires_modifier(&self) -> bool {
 7215        match self.edit_prediction_settings {
 7216            EditPredictionSettings::Disabled => false,
 7217            EditPredictionSettings::Enabled {
 7218                preview_requires_modifier,
 7219                ..
 7220            } => preview_requires_modifier,
 7221        }
 7222    }
 7223
 7224    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7225        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7226            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7227            self.discard_edit_prediction(false, cx);
 7228        } else {
 7229            let selection = self.selections.newest_anchor();
 7230            let cursor = selection.head();
 7231
 7232            if let Some((buffer, cursor_buffer_position)) =
 7233                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7234            {
 7235                self.edit_prediction_settings =
 7236                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7237            }
 7238        }
 7239    }
 7240
 7241    fn edit_prediction_settings_at_position(
 7242        &self,
 7243        buffer: &Entity<Buffer>,
 7244        buffer_position: language::Anchor,
 7245        cx: &App,
 7246    ) -> EditPredictionSettings {
 7247        if !self.mode.is_full()
 7248            || !self.show_edit_predictions_override.unwrap_or(true)
 7249            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7250        {
 7251            return EditPredictionSettings::Disabled;
 7252        }
 7253
 7254        let buffer = buffer.read(cx);
 7255
 7256        let file = buffer.file();
 7257
 7258        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7259            return EditPredictionSettings::Disabled;
 7260        };
 7261
 7262        let by_provider = matches!(
 7263            self.menu_edit_predictions_policy,
 7264            MenuEditPredictionsPolicy::ByProvider
 7265        );
 7266
 7267        let show_in_menu = by_provider
 7268            && self
 7269                .edit_prediction_provider
 7270                .as_ref()
 7271                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7272
 7273        let preview_requires_modifier =
 7274            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7275
 7276        EditPredictionSettings::Enabled {
 7277            show_in_menu,
 7278            preview_requires_modifier,
 7279        }
 7280    }
 7281
 7282    fn should_show_edit_predictions(&self) -> bool {
 7283        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7284    }
 7285
 7286    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7287        matches!(
 7288            self.edit_prediction_preview,
 7289            EditPredictionPreview::Active { .. }
 7290        )
 7291    }
 7292
 7293    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7294        let cursor = self.selections.newest_anchor().head();
 7295        if let Some((buffer, cursor_position)) =
 7296            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7297        {
 7298            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7299        } else {
 7300            false
 7301        }
 7302    }
 7303
 7304    pub fn supports_minimap(&self, cx: &App) -> bool {
 7305        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7306    }
 7307
 7308    fn edit_predictions_enabled_in_buffer(
 7309        &self,
 7310        buffer: &Entity<Buffer>,
 7311        buffer_position: language::Anchor,
 7312        cx: &App,
 7313    ) -> bool {
 7314        maybe!({
 7315            if self.read_only(cx) {
 7316                return Some(false);
 7317            }
 7318            let provider = self.edit_prediction_provider()?;
 7319            if !provider.is_enabled(buffer, buffer_position, cx) {
 7320                return Some(false);
 7321            }
 7322            let buffer = buffer.read(cx);
 7323            let Some(file) = buffer.file() else {
 7324                return Some(true);
 7325            };
 7326            let settings = all_language_settings(Some(file), cx);
 7327            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7328        })
 7329        .unwrap_or(false)
 7330    }
 7331
 7332    fn cycle_edit_prediction(
 7333        &mut self,
 7334        direction: Direction,
 7335        window: &mut Window,
 7336        cx: &mut Context<Self>,
 7337    ) -> Option<()> {
 7338        let provider = self.edit_prediction_provider()?;
 7339        let cursor = self.selections.newest_anchor().head();
 7340        let (buffer, cursor_buffer_position) =
 7341            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7342        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7343            return None;
 7344        }
 7345
 7346        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7347        self.update_visible_edit_prediction(window, cx);
 7348
 7349        Some(())
 7350    }
 7351
 7352    pub fn show_edit_prediction(
 7353        &mut self,
 7354        _: &ShowEditPrediction,
 7355        window: &mut Window,
 7356        cx: &mut Context<Self>,
 7357    ) {
 7358        if !self.has_active_edit_prediction() {
 7359            self.refresh_edit_prediction(false, true, window, cx);
 7360            return;
 7361        }
 7362
 7363        self.update_visible_edit_prediction(window, cx);
 7364    }
 7365
 7366    pub fn display_cursor_names(
 7367        &mut self,
 7368        _: &DisplayCursorNames,
 7369        window: &mut Window,
 7370        cx: &mut Context<Self>,
 7371    ) {
 7372        self.show_cursor_names(window, cx);
 7373    }
 7374
 7375    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7376        self.show_cursor_names = true;
 7377        cx.notify();
 7378        cx.spawn_in(window, async move |this, cx| {
 7379            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7380            this.update(cx, |this, cx| {
 7381                this.show_cursor_names = false;
 7382                cx.notify()
 7383            })
 7384            .ok()
 7385        })
 7386        .detach();
 7387    }
 7388
 7389    pub fn next_edit_prediction(
 7390        &mut self,
 7391        _: &NextEditPrediction,
 7392        window: &mut Window,
 7393        cx: &mut Context<Self>,
 7394    ) {
 7395        if self.has_active_edit_prediction() {
 7396            self.cycle_edit_prediction(Direction::Next, window, cx);
 7397        } else {
 7398            let is_copilot_disabled = self
 7399                .refresh_edit_prediction(false, true, window, cx)
 7400                .is_none();
 7401            if is_copilot_disabled {
 7402                cx.propagate();
 7403            }
 7404        }
 7405    }
 7406
 7407    pub fn previous_edit_prediction(
 7408        &mut self,
 7409        _: &PreviousEditPrediction,
 7410        window: &mut Window,
 7411        cx: &mut Context<Self>,
 7412    ) {
 7413        if self.has_active_edit_prediction() {
 7414            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7415        } else {
 7416            let is_copilot_disabled = self
 7417                .refresh_edit_prediction(false, true, window, cx)
 7418                .is_none();
 7419            if is_copilot_disabled {
 7420                cx.propagate();
 7421            }
 7422        }
 7423    }
 7424
 7425    pub fn accept_edit_prediction(
 7426        &mut self,
 7427        _: &AcceptEditPrediction,
 7428        window: &mut Window,
 7429        cx: &mut Context<Self>,
 7430    ) {
 7431        if self.show_edit_predictions_in_menu() {
 7432            self.hide_context_menu(window, cx);
 7433        }
 7434
 7435        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7436            return;
 7437        };
 7438
 7439        match &active_edit_prediction.completion {
 7440            EditPrediction::MoveWithin { target, .. } => {
 7441                let target = *target;
 7442
 7443                if let Some(position_map) = &self.last_position_map {
 7444                    if position_map
 7445                        .visible_row_range
 7446                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7447                        || !self.edit_prediction_requires_modifier()
 7448                    {
 7449                        self.unfold_ranges(&[target..target], true, false, cx);
 7450                        // Note that this is also done in vim's handler of the Tab action.
 7451                        self.change_selections(
 7452                            SelectionEffects::scroll(Autoscroll::newest()),
 7453                            window,
 7454                            cx,
 7455                            |selections| {
 7456                                selections.select_anchor_ranges([target..target]);
 7457                            },
 7458                        );
 7459                        self.clear_row_highlights::<EditPredictionPreview>();
 7460
 7461                        self.edit_prediction_preview
 7462                            .set_previous_scroll_position(None);
 7463                    } else {
 7464                        self.edit_prediction_preview
 7465                            .set_previous_scroll_position(Some(
 7466                                position_map.snapshot.scroll_anchor,
 7467                            ));
 7468
 7469                        self.highlight_rows::<EditPredictionPreview>(
 7470                            target..target,
 7471                            cx.theme().colors().editor_highlighted_line_background,
 7472                            RowHighlightOptions {
 7473                                autoscroll: true,
 7474                                ..Default::default()
 7475                            },
 7476                            cx,
 7477                        );
 7478                        self.request_autoscroll(Autoscroll::fit(), cx);
 7479                    }
 7480                }
 7481            }
 7482            EditPrediction::MoveOutside { snapshot, target } => {
 7483                if let Some(workspace) = self.workspace() {
 7484                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7485                        .detach_and_log_err(cx);
 7486                }
 7487            }
 7488            EditPrediction::Edit { edits, .. } => {
 7489                self.report_edit_prediction_event(
 7490                    active_edit_prediction.completion_id.clone(),
 7491                    true,
 7492                    cx,
 7493                );
 7494
 7495                if let Some(provider) = self.edit_prediction_provider() {
 7496                    provider.accept(cx);
 7497                }
 7498
 7499                // Store the transaction ID and selections before applying the edit
 7500                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7501
 7502                let snapshot = self.buffer.read(cx).snapshot(cx);
 7503                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7504
 7505                self.buffer.update(cx, |buffer, cx| {
 7506                    buffer.edit(edits.iter().cloned(), None, cx)
 7507                });
 7508
 7509                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7510                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7511                });
 7512
 7513                let selections = self.selections.disjoint_anchors_arc();
 7514                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7515                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7516                    if has_new_transaction {
 7517                        self.selection_history
 7518                            .insert_transaction(transaction_id_now, selections);
 7519                    }
 7520                }
 7521
 7522                self.update_visible_edit_prediction(window, cx);
 7523                if self.active_edit_prediction.is_none() {
 7524                    self.refresh_edit_prediction(true, true, window, cx);
 7525                }
 7526
 7527                cx.notify();
 7528            }
 7529        }
 7530
 7531        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7532    }
 7533
 7534    pub fn accept_partial_edit_prediction(
 7535        &mut self,
 7536        _: &AcceptPartialEditPrediction,
 7537        window: &mut Window,
 7538        cx: &mut Context<Self>,
 7539    ) {
 7540        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7541            return;
 7542        };
 7543        if self.selections.count() != 1 {
 7544            return;
 7545        }
 7546
 7547        match &active_edit_prediction.completion {
 7548            EditPrediction::MoveWithin { target, .. } => {
 7549                let target = *target;
 7550                self.change_selections(
 7551                    SelectionEffects::scroll(Autoscroll::newest()),
 7552                    window,
 7553                    cx,
 7554                    |selections| {
 7555                        selections.select_anchor_ranges([target..target]);
 7556                    },
 7557                );
 7558            }
 7559            EditPrediction::MoveOutside { snapshot, target } => {
 7560                if let Some(workspace) = self.workspace() {
 7561                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7562                        .detach_and_log_err(cx);
 7563                }
 7564            }
 7565            EditPrediction::Edit { edits, .. } => {
 7566                self.report_edit_prediction_event(
 7567                    active_edit_prediction.completion_id.clone(),
 7568                    true,
 7569                    cx,
 7570                );
 7571
 7572                // Find an insertion that starts at the cursor position.
 7573                let snapshot = self.buffer.read(cx).snapshot(cx);
 7574                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7575                let insertion = edits.iter().find_map(|(range, text)| {
 7576                    let range = range.to_offset(&snapshot);
 7577                    if range.is_empty() && range.start == cursor_offset {
 7578                        Some(text)
 7579                    } else {
 7580                        None
 7581                    }
 7582                });
 7583
 7584                if let Some(text) = insertion {
 7585                    let mut partial_completion = text
 7586                        .chars()
 7587                        .by_ref()
 7588                        .take_while(|c| c.is_alphabetic())
 7589                        .collect::<String>();
 7590                    if partial_completion.is_empty() {
 7591                        partial_completion = text
 7592                            .chars()
 7593                            .by_ref()
 7594                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7595                            .collect::<String>();
 7596                    }
 7597
 7598                    cx.emit(EditorEvent::InputHandled {
 7599                        utf16_range_to_replace: None,
 7600                        text: partial_completion.clone().into(),
 7601                    });
 7602
 7603                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7604
 7605                    self.refresh_edit_prediction(true, true, window, cx);
 7606                    cx.notify();
 7607                } else {
 7608                    self.accept_edit_prediction(&Default::default(), window, cx);
 7609                }
 7610            }
 7611        }
 7612    }
 7613
 7614    fn discard_edit_prediction(
 7615        &mut self,
 7616        should_report_edit_prediction_event: bool,
 7617        cx: &mut Context<Self>,
 7618    ) -> bool {
 7619        if should_report_edit_prediction_event {
 7620            let completion_id = self
 7621                .active_edit_prediction
 7622                .as_ref()
 7623                .and_then(|active_completion| active_completion.completion_id.clone());
 7624
 7625            self.report_edit_prediction_event(completion_id, false, cx);
 7626        }
 7627
 7628        if let Some(provider) = self.edit_prediction_provider() {
 7629            provider.discard(cx);
 7630        }
 7631
 7632        self.take_active_edit_prediction(cx)
 7633    }
 7634
 7635    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7636        let Some(provider) = self.edit_prediction_provider() else {
 7637            return;
 7638        };
 7639
 7640        let Some((_, buffer, _)) = self
 7641            .buffer
 7642            .read(cx)
 7643            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7644        else {
 7645            return;
 7646        };
 7647
 7648        let extension = buffer
 7649            .read(cx)
 7650            .file()
 7651            .and_then(|file| Some(file.path().extension()?.to_string()));
 7652
 7653        let event_type = match accepted {
 7654            true => "Edit Prediction Accepted",
 7655            false => "Edit Prediction Discarded",
 7656        };
 7657        telemetry::event!(
 7658            event_type,
 7659            provider = provider.name(),
 7660            prediction_id = id,
 7661            suggestion_accepted = accepted,
 7662            file_extension = extension,
 7663        );
 7664    }
 7665
 7666    fn open_editor_at_anchor(
 7667        snapshot: &language::BufferSnapshot,
 7668        target: language::Anchor,
 7669        workspace: &Entity<Workspace>,
 7670        window: &mut Window,
 7671        cx: &mut App,
 7672    ) -> Task<Result<()>> {
 7673        workspace.update(cx, |workspace, cx| {
 7674            let path = snapshot.file().map(|file| file.full_path(cx));
 7675            let Some(path) =
 7676                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7677            else {
 7678                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7679            };
 7680            let target = text::ToPoint::to_point(&target, snapshot);
 7681            let item = workspace.open_path(path, None, true, window, cx);
 7682            window.spawn(cx, async move |cx| {
 7683                let Some(editor) = item.await?.downcast::<Editor>() else {
 7684                    return Ok(());
 7685                };
 7686                editor
 7687                    .update_in(cx, |editor, window, cx| {
 7688                        editor.go_to_singleton_buffer_point(target, window, cx);
 7689                    })
 7690                    .ok();
 7691                anyhow::Ok(())
 7692            })
 7693        })
 7694    }
 7695
 7696    pub fn has_active_edit_prediction(&self) -> bool {
 7697        self.active_edit_prediction.is_some()
 7698    }
 7699
 7700    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7701        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7702            return false;
 7703        };
 7704
 7705        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7706        self.clear_highlights::<EditPredictionHighlight>(cx);
 7707        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7708        true
 7709    }
 7710
 7711    /// Returns true when we're displaying the edit prediction popover below the cursor
 7712    /// like we are not previewing and the LSP autocomplete menu is visible
 7713    /// or we are in `when_holding_modifier` mode.
 7714    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7715        if self.edit_prediction_preview_is_active()
 7716            || !self.show_edit_predictions_in_menu()
 7717            || !self.edit_predictions_enabled()
 7718        {
 7719            return false;
 7720        }
 7721
 7722        if self.has_visible_completions_menu() {
 7723            return true;
 7724        }
 7725
 7726        has_completion && self.edit_prediction_requires_modifier()
 7727    }
 7728
 7729    fn handle_modifiers_changed(
 7730        &mut self,
 7731        modifiers: Modifiers,
 7732        position_map: &PositionMap,
 7733        window: &mut Window,
 7734        cx: &mut Context<Self>,
 7735    ) {
 7736        if self.show_edit_predictions_in_menu() {
 7737            self.update_edit_prediction_preview(&modifiers, window, cx);
 7738        }
 7739
 7740        self.update_selection_mode(&modifiers, position_map, window, cx);
 7741
 7742        let mouse_position = window.mouse_position();
 7743        if !position_map.text_hitbox.is_hovered(window) {
 7744            return;
 7745        }
 7746
 7747        self.update_hovered_link(
 7748            position_map.point_for_position(mouse_position),
 7749            &position_map.snapshot,
 7750            modifiers,
 7751            window,
 7752            cx,
 7753        )
 7754    }
 7755
 7756    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7757        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7758        if invert {
 7759            match multi_cursor_setting {
 7760                MultiCursorModifier::Alt => modifiers.alt,
 7761                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7762            }
 7763        } else {
 7764            match multi_cursor_setting {
 7765                MultiCursorModifier::Alt => modifiers.secondary(),
 7766                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7767            }
 7768        }
 7769    }
 7770
 7771    fn columnar_selection_mode(
 7772        modifiers: &Modifiers,
 7773        cx: &mut Context<Self>,
 7774    ) -> Option<ColumnarMode> {
 7775        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7776            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7777                Some(ColumnarMode::FromMouse)
 7778            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7779                Some(ColumnarMode::FromSelection)
 7780            } else {
 7781                None
 7782            }
 7783        } else {
 7784            None
 7785        }
 7786    }
 7787
 7788    fn update_selection_mode(
 7789        &mut self,
 7790        modifiers: &Modifiers,
 7791        position_map: &PositionMap,
 7792        window: &mut Window,
 7793        cx: &mut Context<Self>,
 7794    ) {
 7795        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7796            return;
 7797        };
 7798        if self.selections.pending_anchor().is_none() {
 7799            return;
 7800        }
 7801
 7802        let mouse_position = window.mouse_position();
 7803        let point_for_position = position_map.point_for_position(mouse_position);
 7804        let position = point_for_position.previous_valid;
 7805
 7806        self.select(
 7807            SelectPhase::BeginColumnar {
 7808                position,
 7809                reset: false,
 7810                mode,
 7811                goal_column: point_for_position.exact_unclipped.column(),
 7812            },
 7813            window,
 7814            cx,
 7815        );
 7816    }
 7817
 7818    fn update_edit_prediction_preview(
 7819        &mut self,
 7820        modifiers: &Modifiers,
 7821        window: &mut Window,
 7822        cx: &mut Context<Self>,
 7823    ) {
 7824        let mut modifiers_held = false;
 7825        if let Some(accept_keystroke) = self
 7826            .accept_edit_prediction_keybind(false, window, cx)
 7827            .keystroke()
 7828        {
 7829            modifiers_held = modifiers_held
 7830                || (accept_keystroke.modifiers() == modifiers
 7831                    && accept_keystroke.modifiers().modified());
 7832        };
 7833        if let Some(accept_partial_keystroke) = self
 7834            .accept_edit_prediction_keybind(true, window, cx)
 7835            .keystroke()
 7836        {
 7837            modifiers_held = modifiers_held
 7838                || (accept_partial_keystroke.modifiers() == modifiers
 7839                    && accept_partial_keystroke.modifiers().modified());
 7840        }
 7841
 7842        if modifiers_held {
 7843            if matches!(
 7844                self.edit_prediction_preview,
 7845                EditPredictionPreview::Inactive { .. }
 7846            ) {
 7847                self.edit_prediction_preview = EditPredictionPreview::Active {
 7848                    previous_scroll_position: None,
 7849                    since: Instant::now(),
 7850                };
 7851
 7852                self.update_visible_edit_prediction(window, cx);
 7853                cx.notify();
 7854            }
 7855        } else if let EditPredictionPreview::Active {
 7856            previous_scroll_position,
 7857            since,
 7858        } = self.edit_prediction_preview
 7859        {
 7860            if let (Some(previous_scroll_position), Some(position_map)) =
 7861                (previous_scroll_position, self.last_position_map.as_ref())
 7862            {
 7863                self.set_scroll_position(
 7864                    previous_scroll_position
 7865                        .scroll_position(&position_map.snapshot.display_snapshot),
 7866                    window,
 7867                    cx,
 7868                );
 7869            }
 7870
 7871            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7872                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7873            };
 7874            self.clear_row_highlights::<EditPredictionPreview>();
 7875            self.update_visible_edit_prediction(window, cx);
 7876            cx.notify();
 7877        }
 7878    }
 7879
 7880    fn update_visible_edit_prediction(
 7881        &mut self,
 7882        _window: &mut Window,
 7883        cx: &mut Context<Self>,
 7884    ) -> Option<()> {
 7885        if DisableAiSettings::get_global(cx).disable_ai {
 7886            return None;
 7887        }
 7888
 7889        if self.ime_transaction.is_some() {
 7890            self.discard_edit_prediction(false, cx);
 7891            return None;
 7892        }
 7893
 7894        let selection = self.selections.newest_anchor();
 7895        let cursor = selection.head();
 7896        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7897        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7898        let excerpt_id = cursor.excerpt_id;
 7899
 7900        let show_in_menu = self.show_edit_predictions_in_menu();
 7901        let completions_menu_has_precedence = !show_in_menu
 7902            && (self.context_menu.borrow().is_some()
 7903                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7904
 7905        if completions_menu_has_precedence
 7906            || !offset_selection.is_empty()
 7907            || self
 7908                .active_edit_prediction
 7909                .as_ref()
 7910                .is_some_and(|completion| {
 7911                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7912                        return false;
 7913                    };
 7914                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7915                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7916                    !invalidation_range.contains(&offset_selection.head())
 7917                })
 7918        {
 7919            self.discard_edit_prediction(false, cx);
 7920            return None;
 7921        }
 7922
 7923        self.take_active_edit_prediction(cx);
 7924        let Some(provider) = self.edit_prediction_provider() else {
 7925            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7926            return None;
 7927        };
 7928
 7929        let (buffer, cursor_buffer_position) =
 7930            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7931
 7932        self.edit_prediction_settings =
 7933            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7934
 7935        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7936
 7937        if self.edit_prediction_indent_conflict {
 7938            let cursor_point = cursor.to_point(&multibuffer);
 7939
 7940            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7941
 7942            if let Some((_, indent)) = indents.iter().next()
 7943                && indent.len == cursor_point.column
 7944            {
 7945                self.edit_prediction_indent_conflict = false;
 7946            }
 7947        }
 7948
 7949        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7950
 7951        let (completion_id, edits, edit_preview) = match edit_prediction {
 7952            edit_prediction::EditPrediction::Local {
 7953                id,
 7954                edits,
 7955                edit_preview,
 7956            } => (id, edits, edit_preview),
 7957            edit_prediction::EditPrediction::Jump {
 7958                id,
 7959                snapshot,
 7960                target,
 7961            } => {
 7962                self.stale_edit_prediction_in_menu = None;
 7963                self.active_edit_prediction = Some(EditPredictionState {
 7964                    inlay_ids: vec![],
 7965                    completion: EditPrediction::MoveOutside { snapshot, target },
 7966                    completion_id: id,
 7967                    invalidation_range: None,
 7968                });
 7969                cx.notify();
 7970                return Some(());
 7971            }
 7972        };
 7973
 7974        let edits = edits
 7975            .into_iter()
 7976            .flat_map(|(range, new_text)| {
 7977                Some((
 7978                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7979                    new_text,
 7980                ))
 7981            })
 7982            .collect::<Vec<_>>();
 7983        if edits.is_empty() {
 7984            return None;
 7985        }
 7986
 7987        let first_edit_start = edits.first().unwrap().0.start;
 7988        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7989        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7990
 7991        let last_edit_end = edits.last().unwrap().0.end;
 7992        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7993        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7994
 7995        let cursor_row = cursor.to_point(&multibuffer).row;
 7996
 7997        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7998
 7999        let mut inlay_ids = Vec::new();
 8000        let invalidation_row_range;
 8001        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8002            Some(cursor_row..edit_end_row)
 8003        } else if cursor_row > edit_end_row {
 8004            Some(edit_start_row..cursor_row)
 8005        } else {
 8006            None
 8007        };
 8008        let supports_jump = self
 8009            .edit_prediction_provider
 8010            .as_ref()
 8011            .map(|provider| provider.provider.supports_jump_to_edit())
 8012            .unwrap_or(true);
 8013
 8014        let is_move = supports_jump
 8015            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8016        let completion = if is_move {
 8017            invalidation_row_range =
 8018                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8019            let target = first_edit_start;
 8020            EditPrediction::MoveWithin { target, snapshot }
 8021        } else {
 8022            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8023                && !self.edit_predictions_hidden_for_vim_mode;
 8024
 8025            if show_completions_in_buffer {
 8026                if edits
 8027                    .iter()
 8028                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8029                {
 8030                    let mut inlays = Vec::new();
 8031                    for (range, new_text) in &edits {
 8032                        let inlay = Inlay::edit_prediction(
 8033                            post_inc(&mut self.next_inlay_id),
 8034                            range.start,
 8035                            new_text.as_str(),
 8036                        );
 8037                        inlay_ids.push(inlay.id);
 8038                        inlays.push(inlay);
 8039                    }
 8040
 8041                    self.splice_inlays(&[], inlays, cx);
 8042                } else {
 8043                    let background_color = cx.theme().status().deleted_background;
 8044                    self.highlight_text::<EditPredictionHighlight>(
 8045                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8046                        HighlightStyle {
 8047                            background_color: Some(background_color),
 8048                            ..Default::default()
 8049                        },
 8050                        cx,
 8051                    );
 8052                }
 8053            }
 8054
 8055            invalidation_row_range = edit_start_row..edit_end_row;
 8056
 8057            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8058                if provider.show_tab_accept_marker() {
 8059                    EditDisplayMode::TabAccept
 8060                } else {
 8061                    EditDisplayMode::Inline
 8062                }
 8063            } else {
 8064                EditDisplayMode::DiffPopover
 8065            };
 8066
 8067            EditPrediction::Edit {
 8068                edits,
 8069                edit_preview,
 8070                display_mode,
 8071                snapshot,
 8072            }
 8073        };
 8074
 8075        let invalidation_range = multibuffer
 8076            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8077            ..multibuffer.anchor_after(Point::new(
 8078                invalidation_row_range.end,
 8079                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8080            ));
 8081
 8082        self.stale_edit_prediction_in_menu = None;
 8083        self.active_edit_prediction = Some(EditPredictionState {
 8084            inlay_ids,
 8085            completion,
 8086            completion_id,
 8087            invalidation_range: Some(invalidation_range),
 8088        });
 8089
 8090        cx.notify();
 8091
 8092        Some(())
 8093    }
 8094
 8095    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8096        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8097    }
 8098
 8099    fn clear_tasks(&mut self) {
 8100        self.tasks.clear()
 8101    }
 8102
 8103    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8104        if self.tasks.insert(key, value).is_some() {
 8105            // This case should hopefully be rare, but just in case...
 8106            log::error!(
 8107                "multiple different run targets found on a single line, only the last target will be rendered"
 8108            )
 8109        }
 8110    }
 8111
 8112    /// Get all display points of breakpoints that will be rendered within editor
 8113    ///
 8114    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8115    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8116    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8117    fn active_breakpoints(
 8118        &self,
 8119        range: Range<DisplayRow>,
 8120        window: &mut Window,
 8121        cx: &mut Context<Self>,
 8122    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8123        let mut breakpoint_display_points = HashMap::default();
 8124
 8125        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8126            return breakpoint_display_points;
 8127        };
 8128
 8129        let snapshot = self.snapshot(window, cx);
 8130
 8131        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8132        let Some(project) = self.project() else {
 8133            return breakpoint_display_points;
 8134        };
 8135
 8136        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8137            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8138
 8139        for (buffer_snapshot, range, excerpt_id) in
 8140            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8141        {
 8142            let Some(buffer) = project
 8143                .read(cx)
 8144                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8145            else {
 8146                continue;
 8147            };
 8148            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8149                &buffer,
 8150                Some(
 8151                    buffer_snapshot.anchor_before(range.start)
 8152                        ..buffer_snapshot.anchor_after(range.end),
 8153                ),
 8154                buffer_snapshot,
 8155                cx,
 8156            );
 8157            for (breakpoint, state) in breakpoints {
 8158                let multi_buffer_anchor =
 8159                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8160                let position = multi_buffer_anchor
 8161                    .to_point(multi_buffer_snapshot)
 8162                    .to_display_point(&snapshot);
 8163
 8164                breakpoint_display_points.insert(
 8165                    position.row(),
 8166                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8167                );
 8168            }
 8169        }
 8170
 8171        breakpoint_display_points
 8172    }
 8173
 8174    fn breakpoint_context_menu(
 8175        &self,
 8176        anchor: Anchor,
 8177        window: &mut Window,
 8178        cx: &mut Context<Self>,
 8179    ) -> Entity<ui::ContextMenu> {
 8180        let weak_editor = cx.weak_entity();
 8181        let focus_handle = self.focus_handle(cx);
 8182
 8183        let row = self
 8184            .buffer
 8185            .read(cx)
 8186            .snapshot(cx)
 8187            .summary_for_anchor::<Point>(&anchor)
 8188            .row;
 8189
 8190        let breakpoint = self
 8191            .breakpoint_at_row(row, window, cx)
 8192            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8193
 8194        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8195            "Edit Log Breakpoint"
 8196        } else {
 8197            "Set Log Breakpoint"
 8198        };
 8199
 8200        let condition_breakpoint_msg = if breakpoint
 8201            .as_ref()
 8202            .is_some_and(|bp| bp.1.condition.is_some())
 8203        {
 8204            "Edit Condition Breakpoint"
 8205        } else {
 8206            "Set Condition Breakpoint"
 8207        };
 8208
 8209        let hit_condition_breakpoint_msg = if breakpoint
 8210            .as_ref()
 8211            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8212        {
 8213            "Edit Hit Condition Breakpoint"
 8214        } else {
 8215            "Set Hit Condition Breakpoint"
 8216        };
 8217
 8218        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8219            "Unset Breakpoint"
 8220        } else {
 8221            "Set Breakpoint"
 8222        };
 8223
 8224        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8225
 8226        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8227            BreakpointState::Enabled => Some("Disable"),
 8228            BreakpointState::Disabled => Some("Enable"),
 8229        });
 8230
 8231        let (anchor, breakpoint) =
 8232            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8233
 8234        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8235            menu.on_blur_subscription(Subscription::new(|| {}))
 8236                .context(focus_handle)
 8237                .when(run_to_cursor, |this| {
 8238                    let weak_editor = weak_editor.clone();
 8239                    this.entry("Run to cursor", None, move |window, cx| {
 8240                        weak_editor
 8241                            .update(cx, |editor, cx| {
 8242                                editor.change_selections(
 8243                                    SelectionEffects::no_scroll(),
 8244                                    window,
 8245                                    cx,
 8246                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8247                                );
 8248                            })
 8249                            .ok();
 8250
 8251                        window.dispatch_action(Box::new(RunToCursor), cx);
 8252                    })
 8253                    .separator()
 8254                })
 8255                .when_some(toggle_state_msg, |this, msg| {
 8256                    this.entry(msg, None, {
 8257                        let weak_editor = weak_editor.clone();
 8258                        let breakpoint = breakpoint.clone();
 8259                        move |_window, cx| {
 8260                            weak_editor
 8261                                .update(cx, |this, cx| {
 8262                                    this.edit_breakpoint_at_anchor(
 8263                                        anchor,
 8264                                        breakpoint.as_ref().clone(),
 8265                                        BreakpointEditAction::InvertState,
 8266                                        cx,
 8267                                    );
 8268                                })
 8269                                .log_err();
 8270                        }
 8271                    })
 8272                })
 8273                .entry(set_breakpoint_msg, None, {
 8274                    let weak_editor = weak_editor.clone();
 8275                    let breakpoint = breakpoint.clone();
 8276                    move |_window, cx| {
 8277                        weak_editor
 8278                            .update(cx, |this, cx| {
 8279                                this.edit_breakpoint_at_anchor(
 8280                                    anchor,
 8281                                    breakpoint.as_ref().clone(),
 8282                                    BreakpointEditAction::Toggle,
 8283                                    cx,
 8284                                );
 8285                            })
 8286                            .log_err();
 8287                    }
 8288                })
 8289                .entry(log_breakpoint_msg, None, {
 8290                    let breakpoint = breakpoint.clone();
 8291                    let weak_editor = weak_editor.clone();
 8292                    move |window, cx| {
 8293                        weak_editor
 8294                            .update(cx, |this, cx| {
 8295                                this.add_edit_breakpoint_block(
 8296                                    anchor,
 8297                                    breakpoint.as_ref(),
 8298                                    BreakpointPromptEditAction::Log,
 8299                                    window,
 8300                                    cx,
 8301                                );
 8302                            })
 8303                            .log_err();
 8304                    }
 8305                })
 8306                .entry(condition_breakpoint_msg, None, {
 8307                    let breakpoint = breakpoint.clone();
 8308                    let weak_editor = weak_editor.clone();
 8309                    move |window, cx| {
 8310                        weak_editor
 8311                            .update(cx, |this, cx| {
 8312                                this.add_edit_breakpoint_block(
 8313                                    anchor,
 8314                                    breakpoint.as_ref(),
 8315                                    BreakpointPromptEditAction::Condition,
 8316                                    window,
 8317                                    cx,
 8318                                );
 8319                            })
 8320                            .log_err();
 8321                    }
 8322                })
 8323                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8324                    weak_editor
 8325                        .update(cx, |this, cx| {
 8326                            this.add_edit_breakpoint_block(
 8327                                anchor,
 8328                                breakpoint.as_ref(),
 8329                                BreakpointPromptEditAction::HitCondition,
 8330                                window,
 8331                                cx,
 8332                            );
 8333                        })
 8334                        .log_err();
 8335                })
 8336        })
 8337    }
 8338
 8339    fn render_breakpoint(
 8340        &self,
 8341        position: Anchor,
 8342        row: DisplayRow,
 8343        breakpoint: &Breakpoint,
 8344        state: Option<BreakpointSessionState>,
 8345        cx: &mut Context<Self>,
 8346    ) -> IconButton {
 8347        let is_rejected = state.is_some_and(|s| !s.verified);
 8348        // Is it a breakpoint that shows up when hovering over gutter?
 8349        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8350            (false, false),
 8351            |PhantomBreakpointIndicator {
 8352                 is_active,
 8353                 display_row,
 8354                 collides_with_existing_breakpoint,
 8355             }| {
 8356                (
 8357                    is_active && display_row == row,
 8358                    collides_with_existing_breakpoint,
 8359                )
 8360            },
 8361        );
 8362
 8363        let (color, icon) = {
 8364            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8365                (false, false) => ui::IconName::DebugBreakpoint,
 8366                (true, false) => ui::IconName::DebugLogBreakpoint,
 8367                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8368                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8369            };
 8370
 8371            let color = if is_phantom {
 8372                Color::Hint
 8373            } else if is_rejected {
 8374                Color::Disabled
 8375            } else {
 8376                Color::Debugger
 8377            };
 8378
 8379            (color, icon)
 8380        };
 8381
 8382        let breakpoint = Arc::from(breakpoint.clone());
 8383
 8384        let alt_as_text = gpui::Keystroke {
 8385            modifiers: Modifiers::secondary_key(),
 8386            ..Default::default()
 8387        };
 8388        let primary_action_text = if breakpoint.is_disabled() {
 8389            "Enable breakpoint"
 8390        } else if is_phantom && !collides_with_existing {
 8391            "Set breakpoint"
 8392        } else {
 8393            "Unset breakpoint"
 8394        };
 8395        let focus_handle = self.focus_handle.clone();
 8396
 8397        let meta = if is_rejected {
 8398            SharedString::from("No executable code is associated with this line.")
 8399        } else if collides_with_existing && !breakpoint.is_disabled() {
 8400            SharedString::from(format!(
 8401                "{alt_as_text}-click to disable,\nright-click for more options."
 8402            ))
 8403        } else {
 8404            SharedString::from("Right-click for more options.")
 8405        };
 8406        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8407            .icon_size(IconSize::XSmall)
 8408            .size(ui::ButtonSize::None)
 8409            .when(is_rejected, |this| {
 8410                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8411            })
 8412            .icon_color(color)
 8413            .style(ButtonStyle::Transparent)
 8414            .on_click(cx.listener({
 8415                move |editor, event: &ClickEvent, window, cx| {
 8416                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8417                        BreakpointEditAction::InvertState
 8418                    } else {
 8419                        BreakpointEditAction::Toggle
 8420                    };
 8421
 8422                    window.focus(&editor.focus_handle(cx));
 8423                    editor.edit_breakpoint_at_anchor(
 8424                        position,
 8425                        breakpoint.as_ref().clone(),
 8426                        edit_action,
 8427                        cx,
 8428                    );
 8429                }
 8430            }))
 8431            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8432                editor.set_breakpoint_context_menu(
 8433                    row,
 8434                    Some(position),
 8435                    event.position(),
 8436                    window,
 8437                    cx,
 8438                );
 8439            }))
 8440            .tooltip(move |window, cx| {
 8441                Tooltip::with_meta_in(
 8442                    primary_action_text,
 8443                    Some(&ToggleBreakpoint),
 8444                    meta.clone(),
 8445                    &focus_handle,
 8446                    window,
 8447                    cx,
 8448                )
 8449            })
 8450    }
 8451
 8452    fn build_tasks_context(
 8453        project: &Entity<Project>,
 8454        buffer: &Entity<Buffer>,
 8455        buffer_row: u32,
 8456        tasks: &Arc<RunnableTasks>,
 8457        cx: &mut Context<Self>,
 8458    ) -> Task<Option<task::TaskContext>> {
 8459        let position = Point::new(buffer_row, tasks.column);
 8460        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8461        let location = Location {
 8462            buffer: buffer.clone(),
 8463            range: range_start..range_start,
 8464        };
 8465        // Fill in the environmental variables from the tree-sitter captures
 8466        let mut captured_task_variables = TaskVariables::default();
 8467        for (capture_name, value) in tasks.extra_variables.clone() {
 8468            captured_task_variables.insert(
 8469                task::VariableName::Custom(capture_name.into()),
 8470                value.clone(),
 8471            );
 8472        }
 8473        project.update(cx, |project, cx| {
 8474            project.task_store().update(cx, |task_store, cx| {
 8475                task_store.task_context_for_location(captured_task_variables, location, cx)
 8476            })
 8477        })
 8478    }
 8479
 8480    pub fn spawn_nearest_task(
 8481        &mut self,
 8482        action: &SpawnNearestTask,
 8483        window: &mut Window,
 8484        cx: &mut Context<Self>,
 8485    ) {
 8486        let Some((workspace, _)) = self.workspace.clone() else {
 8487            return;
 8488        };
 8489        let Some(project) = self.project.clone() else {
 8490            return;
 8491        };
 8492
 8493        // Try to find a closest, enclosing node using tree-sitter that has a task
 8494        let Some((buffer, buffer_row, tasks)) = self
 8495            .find_enclosing_node_task(cx)
 8496            // Or find the task that's closest in row-distance.
 8497            .or_else(|| self.find_closest_task(cx))
 8498        else {
 8499            return;
 8500        };
 8501
 8502        let reveal_strategy = action.reveal;
 8503        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8504        cx.spawn_in(window, async move |_, cx| {
 8505            let context = task_context.await?;
 8506            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8507
 8508            let resolved = &mut resolved_task.resolved;
 8509            resolved.reveal = reveal_strategy;
 8510
 8511            workspace
 8512                .update_in(cx, |workspace, window, cx| {
 8513                    workspace.schedule_resolved_task(
 8514                        task_source_kind,
 8515                        resolved_task,
 8516                        false,
 8517                        window,
 8518                        cx,
 8519                    );
 8520                })
 8521                .ok()
 8522        })
 8523        .detach();
 8524    }
 8525
 8526    fn find_closest_task(
 8527        &mut self,
 8528        cx: &mut Context<Self>,
 8529    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8530        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8531
 8532        let ((buffer_id, row), tasks) = self
 8533            .tasks
 8534            .iter()
 8535            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8536
 8537        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8538        let tasks = Arc::new(tasks.to_owned());
 8539        Some((buffer, *row, tasks))
 8540    }
 8541
 8542    fn find_enclosing_node_task(
 8543        &mut self,
 8544        cx: &mut Context<Self>,
 8545    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8546        let snapshot = self.buffer.read(cx).snapshot(cx);
 8547        let offset = self.selections.newest::<usize>(cx).head();
 8548        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8549        let buffer_id = excerpt.buffer().remote_id();
 8550
 8551        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8552        let mut cursor = layer.node().walk();
 8553
 8554        while cursor.goto_first_child_for_byte(offset).is_some() {
 8555            if cursor.node().end_byte() == offset {
 8556                cursor.goto_next_sibling();
 8557            }
 8558        }
 8559
 8560        // Ascend to the smallest ancestor that contains the range and has a task.
 8561        loop {
 8562            let node = cursor.node();
 8563            let node_range = node.byte_range();
 8564            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8565
 8566            // Check if this node contains our offset
 8567            if node_range.start <= offset && node_range.end >= offset {
 8568                // If it contains offset, check for task
 8569                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8570                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8571                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8572                }
 8573            }
 8574
 8575            if !cursor.goto_parent() {
 8576                break;
 8577            }
 8578        }
 8579        None
 8580    }
 8581
 8582    fn render_run_indicator(
 8583        &self,
 8584        _style: &EditorStyle,
 8585        is_active: bool,
 8586        row: DisplayRow,
 8587        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8588        cx: &mut Context<Self>,
 8589    ) -> IconButton {
 8590        let color = Color::Muted;
 8591        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8592
 8593        IconButton::new(
 8594            ("run_indicator", row.0 as usize),
 8595            ui::IconName::PlayOutlined,
 8596        )
 8597        .shape(ui::IconButtonShape::Square)
 8598        .icon_size(IconSize::XSmall)
 8599        .icon_color(color)
 8600        .toggle_state(is_active)
 8601        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8602            let quick_launch = match e {
 8603                ClickEvent::Keyboard(_) => true,
 8604                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8605            };
 8606
 8607            window.focus(&editor.focus_handle(cx));
 8608            editor.toggle_code_actions(
 8609                &ToggleCodeActions {
 8610                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8611                    quick_launch,
 8612                },
 8613                window,
 8614                cx,
 8615            );
 8616        }))
 8617        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8618            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8619        }))
 8620    }
 8621
 8622    pub fn context_menu_visible(&self) -> bool {
 8623        !self.edit_prediction_preview_is_active()
 8624            && self
 8625                .context_menu
 8626                .borrow()
 8627                .as_ref()
 8628                .is_some_and(|menu| menu.visible())
 8629    }
 8630
 8631    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8632        self.context_menu
 8633            .borrow()
 8634            .as_ref()
 8635            .map(|menu| menu.origin())
 8636    }
 8637
 8638    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8639        self.context_menu_options = Some(options);
 8640    }
 8641
 8642    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8643    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8644
 8645    fn render_edit_prediction_popover(
 8646        &mut self,
 8647        text_bounds: &Bounds<Pixels>,
 8648        content_origin: gpui::Point<Pixels>,
 8649        right_margin: Pixels,
 8650        editor_snapshot: &EditorSnapshot,
 8651        visible_row_range: Range<DisplayRow>,
 8652        scroll_top: ScrollOffset,
 8653        scroll_bottom: ScrollOffset,
 8654        line_layouts: &[LineWithInvisibles],
 8655        line_height: Pixels,
 8656        scroll_position: gpui::Point<ScrollOffset>,
 8657        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8658        newest_selection_head: Option<DisplayPoint>,
 8659        editor_width: Pixels,
 8660        style: &EditorStyle,
 8661        window: &mut Window,
 8662        cx: &mut App,
 8663    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8664        if self.mode().is_minimap() {
 8665            return None;
 8666        }
 8667        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8668
 8669        if self.edit_prediction_visible_in_cursor_popover(true) {
 8670            return None;
 8671        }
 8672
 8673        match &active_edit_prediction.completion {
 8674            EditPrediction::MoveWithin { target, .. } => {
 8675                let target_display_point = target.to_display_point(editor_snapshot);
 8676
 8677                if self.edit_prediction_requires_modifier() {
 8678                    if !self.edit_prediction_preview_is_active() {
 8679                        return None;
 8680                    }
 8681
 8682                    self.render_edit_prediction_modifier_jump_popover(
 8683                        text_bounds,
 8684                        content_origin,
 8685                        visible_row_range,
 8686                        line_layouts,
 8687                        line_height,
 8688                        scroll_pixel_position,
 8689                        newest_selection_head,
 8690                        target_display_point,
 8691                        window,
 8692                        cx,
 8693                    )
 8694                } else {
 8695                    self.render_edit_prediction_eager_jump_popover(
 8696                        text_bounds,
 8697                        content_origin,
 8698                        editor_snapshot,
 8699                        visible_row_range,
 8700                        scroll_top,
 8701                        scroll_bottom,
 8702                        line_height,
 8703                        scroll_pixel_position,
 8704                        target_display_point,
 8705                        editor_width,
 8706                        window,
 8707                        cx,
 8708                    )
 8709                }
 8710            }
 8711            EditPrediction::Edit {
 8712                display_mode: EditDisplayMode::Inline,
 8713                ..
 8714            } => None,
 8715            EditPrediction::Edit {
 8716                display_mode: EditDisplayMode::TabAccept,
 8717                edits,
 8718                ..
 8719            } => {
 8720                let range = &edits.first()?.0;
 8721                let target_display_point = range.end.to_display_point(editor_snapshot);
 8722
 8723                self.render_edit_prediction_end_of_line_popover(
 8724                    "Accept",
 8725                    editor_snapshot,
 8726                    visible_row_range,
 8727                    target_display_point,
 8728                    line_height,
 8729                    scroll_pixel_position,
 8730                    content_origin,
 8731                    editor_width,
 8732                    window,
 8733                    cx,
 8734                )
 8735            }
 8736            EditPrediction::Edit {
 8737                edits,
 8738                edit_preview,
 8739                display_mode: EditDisplayMode::DiffPopover,
 8740                snapshot,
 8741            } => self.render_edit_prediction_diff_popover(
 8742                text_bounds,
 8743                content_origin,
 8744                right_margin,
 8745                editor_snapshot,
 8746                visible_row_range,
 8747                line_layouts,
 8748                line_height,
 8749                scroll_position,
 8750                scroll_pixel_position,
 8751                newest_selection_head,
 8752                editor_width,
 8753                style,
 8754                edits,
 8755                edit_preview,
 8756                snapshot,
 8757                window,
 8758                cx,
 8759            ),
 8760            EditPrediction::MoveOutside { snapshot, .. } => {
 8761                let file_name = snapshot
 8762                    .file()
 8763                    .map(|file| file.file_name(cx))
 8764                    .unwrap_or("untitled");
 8765                let mut element = self
 8766                    .render_edit_prediction_line_popover(
 8767                        format!("Jump to {file_name}"),
 8768                        Some(IconName::ZedPredict),
 8769                        window,
 8770                        cx,
 8771                    )
 8772                    .into_any();
 8773
 8774                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8775                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8776                let origin_y = text_bounds.size.height - size.height - px(30.);
 8777                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8778                element.prepaint_at(origin, window, cx);
 8779
 8780                Some((element, origin))
 8781            }
 8782        }
 8783    }
 8784
 8785    fn render_edit_prediction_modifier_jump_popover(
 8786        &mut self,
 8787        text_bounds: &Bounds<Pixels>,
 8788        content_origin: gpui::Point<Pixels>,
 8789        visible_row_range: Range<DisplayRow>,
 8790        line_layouts: &[LineWithInvisibles],
 8791        line_height: Pixels,
 8792        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8793        newest_selection_head: Option<DisplayPoint>,
 8794        target_display_point: DisplayPoint,
 8795        window: &mut Window,
 8796        cx: &mut App,
 8797    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8798        let scrolled_content_origin =
 8799            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8800
 8801        const SCROLL_PADDING_Y: Pixels = px(12.);
 8802
 8803        if target_display_point.row() < visible_row_range.start {
 8804            return self.render_edit_prediction_scroll_popover(
 8805                |_| SCROLL_PADDING_Y,
 8806                IconName::ArrowUp,
 8807                visible_row_range,
 8808                line_layouts,
 8809                newest_selection_head,
 8810                scrolled_content_origin,
 8811                window,
 8812                cx,
 8813            );
 8814        } else if target_display_point.row() >= visible_row_range.end {
 8815            return self.render_edit_prediction_scroll_popover(
 8816                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8817                IconName::ArrowDown,
 8818                visible_row_range,
 8819                line_layouts,
 8820                newest_selection_head,
 8821                scrolled_content_origin,
 8822                window,
 8823                cx,
 8824            );
 8825        }
 8826
 8827        const POLE_WIDTH: Pixels = px(2.);
 8828
 8829        let line_layout =
 8830            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8831        let target_column = target_display_point.column() as usize;
 8832
 8833        let target_x = line_layout.x_for_index(target_column);
 8834        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8835            - scroll_pixel_position.y;
 8836
 8837        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8838
 8839        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8840        border_color.l += 0.001;
 8841
 8842        let mut element = v_flex()
 8843            .items_end()
 8844            .when(flag_on_right, |el| el.items_start())
 8845            .child(if flag_on_right {
 8846                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8847                    .rounded_bl(px(0.))
 8848                    .rounded_tl(px(0.))
 8849                    .border_l_2()
 8850                    .border_color(border_color)
 8851            } else {
 8852                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8853                    .rounded_br(px(0.))
 8854                    .rounded_tr(px(0.))
 8855                    .border_r_2()
 8856                    .border_color(border_color)
 8857            })
 8858            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8859            .into_any();
 8860
 8861        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8862
 8863        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8864            - point(
 8865                if flag_on_right {
 8866                    POLE_WIDTH
 8867                } else {
 8868                    size.width - POLE_WIDTH
 8869                },
 8870                size.height - line_height,
 8871            );
 8872
 8873        origin.x = origin.x.max(content_origin.x);
 8874
 8875        element.prepaint_at(origin, window, cx);
 8876
 8877        Some((element, origin))
 8878    }
 8879
 8880    fn render_edit_prediction_scroll_popover(
 8881        &mut self,
 8882        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8883        scroll_icon: IconName,
 8884        visible_row_range: Range<DisplayRow>,
 8885        line_layouts: &[LineWithInvisibles],
 8886        newest_selection_head: Option<DisplayPoint>,
 8887        scrolled_content_origin: gpui::Point<Pixels>,
 8888        window: &mut Window,
 8889        cx: &mut App,
 8890    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8891        let mut element = self
 8892            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8893            .into_any();
 8894
 8895        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8896
 8897        let cursor = newest_selection_head?;
 8898        let cursor_row_layout =
 8899            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8900        let cursor_column = cursor.column() as usize;
 8901
 8902        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8903
 8904        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8905
 8906        element.prepaint_at(origin, window, cx);
 8907        Some((element, origin))
 8908    }
 8909
 8910    fn render_edit_prediction_eager_jump_popover(
 8911        &mut self,
 8912        text_bounds: &Bounds<Pixels>,
 8913        content_origin: gpui::Point<Pixels>,
 8914        editor_snapshot: &EditorSnapshot,
 8915        visible_row_range: Range<DisplayRow>,
 8916        scroll_top: ScrollOffset,
 8917        scroll_bottom: ScrollOffset,
 8918        line_height: Pixels,
 8919        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8920        target_display_point: DisplayPoint,
 8921        editor_width: Pixels,
 8922        window: &mut Window,
 8923        cx: &mut App,
 8924    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8925        if target_display_point.row().as_f64() < scroll_top {
 8926            let mut element = self
 8927                .render_edit_prediction_line_popover(
 8928                    "Jump to Edit",
 8929                    Some(IconName::ArrowUp),
 8930                    window,
 8931                    cx,
 8932                )
 8933                .into_any();
 8934
 8935            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8936            let offset = point(
 8937                (text_bounds.size.width - size.width) / 2.,
 8938                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8939            );
 8940
 8941            let origin = text_bounds.origin + offset;
 8942            element.prepaint_at(origin, window, cx);
 8943            Some((element, origin))
 8944        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8945            let mut element = self
 8946                .render_edit_prediction_line_popover(
 8947                    "Jump to Edit",
 8948                    Some(IconName::ArrowDown),
 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                text_bounds.size.height - size.height - 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 {
 8964            self.render_edit_prediction_end_of_line_popover(
 8965                "Jump to Edit",
 8966                editor_snapshot,
 8967                visible_row_range,
 8968                target_display_point,
 8969                line_height,
 8970                scroll_pixel_position,
 8971                content_origin,
 8972                editor_width,
 8973                window,
 8974                cx,
 8975            )
 8976        }
 8977    }
 8978
 8979    fn render_edit_prediction_end_of_line_popover(
 8980        self: &mut Editor,
 8981        label: &'static str,
 8982        editor_snapshot: &EditorSnapshot,
 8983        visible_row_range: Range<DisplayRow>,
 8984        target_display_point: DisplayPoint,
 8985        line_height: Pixels,
 8986        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8987        content_origin: gpui::Point<Pixels>,
 8988        editor_width: Pixels,
 8989        window: &mut Window,
 8990        cx: &mut App,
 8991    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8992        let target_line_end = DisplayPoint::new(
 8993            target_display_point.row(),
 8994            editor_snapshot.line_len(target_display_point.row()),
 8995        );
 8996
 8997        let mut element = self
 8998            .render_edit_prediction_line_popover(label, None, window, cx)
 8999            .into_any();
 9000
 9001        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9002
 9003        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9004
 9005        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9006        let mut origin = start_point
 9007            + line_origin
 9008            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9009        origin.x = origin.x.max(content_origin.x);
 9010
 9011        let max_x = content_origin.x + editor_width - size.width;
 9012
 9013        if origin.x > max_x {
 9014            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9015
 9016            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9017                origin.y += offset;
 9018                IconName::ArrowUp
 9019            } else {
 9020                origin.y -= offset;
 9021                IconName::ArrowDown
 9022            };
 9023
 9024            element = self
 9025                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9026                .into_any();
 9027
 9028            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9029
 9030            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9031        }
 9032
 9033        element.prepaint_at(origin, window, cx);
 9034        Some((element, origin))
 9035    }
 9036
 9037    fn render_edit_prediction_diff_popover(
 9038        self: &Editor,
 9039        text_bounds: &Bounds<Pixels>,
 9040        content_origin: gpui::Point<Pixels>,
 9041        right_margin: Pixels,
 9042        editor_snapshot: &EditorSnapshot,
 9043        visible_row_range: Range<DisplayRow>,
 9044        line_layouts: &[LineWithInvisibles],
 9045        line_height: Pixels,
 9046        scroll_position: gpui::Point<ScrollOffset>,
 9047        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9048        newest_selection_head: Option<DisplayPoint>,
 9049        editor_width: Pixels,
 9050        style: &EditorStyle,
 9051        edits: &Vec<(Range<Anchor>, String)>,
 9052        edit_preview: &Option<language::EditPreview>,
 9053        snapshot: &language::BufferSnapshot,
 9054        window: &mut Window,
 9055        cx: &mut App,
 9056    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9057        let edit_start = edits
 9058            .first()
 9059            .unwrap()
 9060            .0
 9061            .start
 9062            .to_display_point(editor_snapshot);
 9063        let edit_end = edits
 9064            .last()
 9065            .unwrap()
 9066            .0
 9067            .end
 9068            .to_display_point(editor_snapshot);
 9069
 9070        let is_visible = visible_row_range.contains(&edit_start.row())
 9071            || visible_row_range.contains(&edit_end.row());
 9072        if !is_visible {
 9073            return None;
 9074        }
 9075
 9076        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9077            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9078        } else {
 9079            // Fallback for providers without edit_preview
 9080            crate::edit_prediction_fallback_text(edits, cx)
 9081        };
 9082
 9083        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9084        let line_count = highlighted_edits.text.lines().count();
 9085
 9086        const BORDER_WIDTH: Pixels = px(1.);
 9087
 9088        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9089        let has_keybind = keybind.is_some();
 9090
 9091        let mut element = h_flex()
 9092            .items_start()
 9093            .child(
 9094                h_flex()
 9095                    .bg(cx.theme().colors().editor_background)
 9096                    .border(BORDER_WIDTH)
 9097                    .shadow_xs()
 9098                    .border_color(cx.theme().colors().border)
 9099                    .rounded_l_lg()
 9100                    .when(line_count > 1, |el| el.rounded_br_lg())
 9101                    .pr_1()
 9102                    .child(styled_text),
 9103            )
 9104            .child(
 9105                h_flex()
 9106                    .h(line_height + BORDER_WIDTH * 2.)
 9107                    .px_1p5()
 9108                    .gap_1()
 9109                    // Workaround: For some reason, there's a gap if we don't do this
 9110                    .ml(-BORDER_WIDTH)
 9111                    .shadow(vec![gpui::BoxShadow {
 9112                        color: gpui::black().opacity(0.05),
 9113                        offset: point(px(1.), px(1.)),
 9114                        blur_radius: px(2.),
 9115                        spread_radius: px(0.),
 9116                    }])
 9117                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9118                    .border(BORDER_WIDTH)
 9119                    .border_color(cx.theme().colors().border)
 9120                    .rounded_r_lg()
 9121                    .id("edit_prediction_diff_popover_keybind")
 9122                    .when(!has_keybind, |el| {
 9123                        let status_colors = cx.theme().status();
 9124
 9125                        el.bg(status_colors.error_background)
 9126                            .border_color(status_colors.error.opacity(0.6))
 9127                            .child(Icon::new(IconName::Info).color(Color::Error))
 9128                            .cursor_default()
 9129                            .hoverable_tooltip(move |_window, cx| {
 9130                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9131                            })
 9132                    })
 9133                    .children(keybind),
 9134            )
 9135            .into_any();
 9136
 9137        let longest_row =
 9138            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9139        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9140            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9141        } else {
 9142            layout_line(
 9143                longest_row,
 9144                editor_snapshot,
 9145                style,
 9146                editor_width,
 9147                |_| false,
 9148                window,
 9149                cx,
 9150            )
 9151            .width
 9152        };
 9153
 9154        let viewport_bounds =
 9155            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9156                right: -right_margin,
 9157                ..Default::default()
 9158            });
 9159
 9160        let x_after_longest = Pixels::from(
 9161            ScrollPixelOffset::from(
 9162                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9163            ) - scroll_pixel_position.x,
 9164        );
 9165
 9166        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9167
 9168        // Fully visible if it can be displayed within the window (allow overlapping other
 9169        // panes). However, this is only allowed if the popover starts within text_bounds.
 9170        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9171            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9172
 9173        let mut origin = if can_position_to_the_right {
 9174            point(
 9175                x_after_longest,
 9176                text_bounds.origin.y
 9177                    + Pixels::from(
 9178                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9179                            - scroll_pixel_position.y,
 9180                    ),
 9181            )
 9182        } else {
 9183            let cursor_row = newest_selection_head.map(|head| head.row());
 9184            let above_edit = edit_start
 9185                .row()
 9186                .0
 9187                .checked_sub(line_count as u32)
 9188                .map(DisplayRow);
 9189            let below_edit = Some(edit_end.row() + 1);
 9190            let above_cursor =
 9191                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9192            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9193
 9194            // Place the edit popover adjacent to the edit if there is a location
 9195            // available that is onscreen and does not obscure the cursor. Otherwise,
 9196            // place it adjacent to the cursor.
 9197            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9198                .into_iter()
 9199                .flatten()
 9200                .find(|&start_row| {
 9201                    let end_row = start_row + line_count as u32;
 9202                    visible_row_range.contains(&start_row)
 9203                        && visible_row_range.contains(&end_row)
 9204                        && cursor_row
 9205                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9206                })?;
 9207
 9208            content_origin
 9209                + point(
 9210                    Pixels::from(-scroll_pixel_position.x),
 9211                    Pixels::from(
 9212                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9213                    ),
 9214                )
 9215        };
 9216
 9217        origin.x -= BORDER_WIDTH;
 9218
 9219        window.defer_draw(element, origin, 1);
 9220
 9221        // Do not return an element, since it will already be drawn due to defer_draw.
 9222        None
 9223    }
 9224
 9225    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9226        px(30.)
 9227    }
 9228
 9229    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9230        if self.read_only(cx) {
 9231            cx.theme().players().read_only()
 9232        } else {
 9233            self.style.as_ref().unwrap().local_player
 9234        }
 9235    }
 9236
 9237    fn render_edit_prediction_accept_keybind(
 9238        &self,
 9239        window: &mut Window,
 9240        cx: &App,
 9241    ) -> Option<AnyElement> {
 9242        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9243        let accept_keystroke = accept_binding.keystroke()?;
 9244
 9245        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9246
 9247        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9248            Color::Accent
 9249        } else {
 9250            Color::Muted
 9251        };
 9252
 9253        h_flex()
 9254            .px_0p5()
 9255            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9256            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9257            .text_size(TextSize::XSmall.rems(cx))
 9258            .child(h_flex().children(ui::render_modifiers(
 9259                accept_keystroke.modifiers(),
 9260                PlatformStyle::platform(),
 9261                Some(modifiers_color),
 9262                Some(IconSize::XSmall.rems().into()),
 9263                true,
 9264            )))
 9265            .when(is_platform_style_mac, |parent| {
 9266                parent.child(accept_keystroke.key().to_string())
 9267            })
 9268            .when(!is_platform_style_mac, |parent| {
 9269                parent.child(
 9270                    Key::new(
 9271                        util::capitalize(accept_keystroke.key()),
 9272                        Some(Color::Default),
 9273                    )
 9274                    .size(Some(IconSize::XSmall.rems().into())),
 9275                )
 9276            })
 9277            .into_any()
 9278            .into()
 9279    }
 9280
 9281    fn render_edit_prediction_line_popover(
 9282        &self,
 9283        label: impl Into<SharedString>,
 9284        icon: Option<IconName>,
 9285        window: &mut Window,
 9286        cx: &App,
 9287    ) -> Stateful<Div> {
 9288        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9289
 9290        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9291        let has_keybind = keybind.is_some();
 9292
 9293        h_flex()
 9294            .id("ep-line-popover")
 9295            .py_0p5()
 9296            .pl_1()
 9297            .pr(padding_right)
 9298            .gap_1()
 9299            .rounded_md()
 9300            .border_1()
 9301            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9302            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9303            .shadow_xs()
 9304            .when(!has_keybind, |el| {
 9305                let status_colors = cx.theme().status();
 9306
 9307                el.bg(status_colors.error_background)
 9308                    .border_color(status_colors.error.opacity(0.6))
 9309                    .pl_2()
 9310                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9311                    .cursor_default()
 9312                    .hoverable_tooltip(move |_window, cx| {
 9313                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9314                    })
 9315            })
 9316            .children(keybind)
 9317            .child(
 9318                Label::new(label)
 9319                    .size(LabelSize::Small)
 9320                    .when(!has_keybind, |el| {
 9321                        el.color(cx.theme().status().error.into()).strikethrough()
 9322                    }),
 9323            )
 9324            .when(!has_keybind, |el| {
 9325                el.child(
 9326                    h_flex().ml_1().child(
 9327                        Icon::new(IconName::Info)
 9328                            .size(IconSize::Small)
 9329                            .color(cx.theme().status().error.into()),
 9330                    ),
 9331                )
 9332            })
 9333            .when_some(icon, |element, icon| {
 9334                element.child(
 9335                    div()
 9336                        .mt(px(1.5))
 9337                        .child(Icon::new(icon).size(IconSize::Small)),
 9338                )
 9339            })
 9340    }
 9341
 9342    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9343        let accent_color = cx.theme().colors().text_accent;
 9344        let editor_bg_color = cx.theme().colors().editor_background;
 9345        editor_bg_color.blend(accent_color.opacity(0.1))
 9346    }
 9347
 9348    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9349        let accent_color = cx.theme().colors().text_accent;
 9350        let editor_bg_color = cx.theme().colors().editor_background;
 9351        editor_bg_color.blend(accent_color.opacity(0.6))
 9352    }
 9353    fn get_prediction_provider_icon_name(
 9354        provider: &Option<RegisteredEditPredictionProvider>,
 9355    ) -> IconName {
 9356        match provider {
 9357            Some(provider) => match provider.provider.name() {
 9358                "copilot" => IconName::Copilot,
 9359                "supermaven" => IconName::Supermaven,
 9360                _ => IconName::ZedPredict,
 9361            },
 9362            None => IconName::ZedPredict,
 9363        }
 9364    }
 9365
 9366    fn render_edit_prediction_cursor_popover(
 9367        &self,
 9368        min_width: Pixels,
 9369        max_width: Pixels,
 9370        cursor_point: Point,
 9371        style: &EditorStyle,
 9372        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9373        _window: &Window,
 9374        cx: &mut Context<Editor>,
 9375    ) -> Option<AnyElement> {
 9376        let provider = self.edit_prediction_provider.as_ref()?;
 9377        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9378
 9379        let is_refreshing = provider.provider.is_refreshing(cx);
 9380
 9381        fn pending_completion_container(icon: IconName) -> Div {
 9382            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9383        }
 9384
 9385        let completion = match &self.active_edit_prediction {
 9386            Some(prediction) => {
 9387                if !self.has_visible_completions_menu() {
 9388                    const RADIUS: Pixels = px(6.);
 9389                    const BORDER_WIDTH: Pixels = px(1.);
 9390
 9391                    return Some(
 9392                        h_flex()
 9393                            .elevation_2(cx)
 9394                            .border(BORDER_WIDTH)
 9395                            .border_color(cx.theme().colors().border)
 9396                            .when(accept_keystroke.is_none(), |el| {
 9397                                el.border_color(cx.theme().status().error)
 9398                            })
 9399                            .rounded(RADIUS)
 9400                            .rounded_tl(px(0.))
 9401                            .overflow_hidden()
 9402                            .child(div().px_1p5().child(match &prediction.completion {
 9403                                EditPrediction::MoveWithin { target, snapshot } => {
 9404                                    use text::ToPoint as _;
 9405                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9406                                    {
 9407                                        Icon::new(IconName::ZedPredictDown)
 9408                                    } else {
 9409                                        Icon::new(IconName::ZedPredictUp)
 9410                                    }
 9411                                }
 9412                                EditPrediction::MoveOutside { .. } => {
 9413                                    // TODO [zeta2] custom icon for external jump?
 9414                                    Icon::new(provider_icon)
 9415                                }
 9416                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9417                            }))
 9418                            .child(
 9419                                h_flex()
 9420                                    .gap_1()
 9421                                    .py_1()
 9422                                    .px_2()
 9423                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9424                                    .border_l_1()
 9425                                    .border_color(cx.theme().colors().border)
 9426                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9427                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9428                                        el.child(
 9429                                            Label::new("Hold")
 9430                                                .size(LabelSize::Small)
 9431                                                .when(accept_keystroke.is_none(), |el| {
 9432                                                    el.strikethrough()
 9433                                                })
 9434                                                .line_height_style(LineHeightStyle::UiLabel),
 9435                                        )
 9436                                    })
 9437                                    .id("edit_prediction_cursor_popover_keybind")
 9438                                    .when(accept_keystroke.is_none(), |el| {
 9439                                        let status_colors = cx.theme().status();
 9440
 9441                                        el.bg(status_colors.error_background)
 9442                                            .border_color(status_colors.error.opacity(0.6))
 9443                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9444                                            .cursor_default()
 9445                                            .hoverable_tooltip(move |_window, cx| {
 9446                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9447                                                    .into()
 9448                                            })
 9449                                    })
 9450                                    .when_some(
 9451                                        accept_keystroke.as_ref(),
 9452                                        |el, accept_keystroke| {
 9453                                            el.child(h_flex().children(ui::render_modifiers(
 9454                                                accept_keystroke.modifiers(),
 9455                                                PlatformStyle::platform(),
 9456                                                Some(Color::Default),
 9457                                                Some(IconSize::XSmall.rems().into()),
 9458                                                false,
 9459                                            )))
 9460                                        },
 9461                                    ),
 9462                            )
 9463                            .into_any(),
 9464                    );
 9465                }
 9466
 9467                self.render_edit_prediction_cursor_popover_preview(
 9468                    prediction,
 9469                    cursor_point,
 9470                    style,
 9471                    cx,
 9472                )?
 9473            }
 9474
 9475            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9476                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9477                    stale_completion,
 9478                    cursor_point,
 9479                    style,
 9480                    cx,
 9481                )?,
 9482
 9483                None => pending_completion_container(provider_icon)
 9484                    .child(Label::new("...").size(LabelSize::Small)),
 9485            },
 9486
 9487            None => pending_completion_container(provider_icon)
 9488                .child(Label::new("...").size(LabelSize::Small)),
 9489        };
 9490
 9491        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9492            completion
 9493                .with_animation(
 9494                    "loading-completion",
 9495                    Animation::new(Duration::from_secs(2))
 9496                        .repeat()
 9497                        .with_easing(pulsating_between(0.4, 0.8)),
 9498                    |label, delta| label.opacity(delta),
 9499                )
 9500                .into_any_element()
 9501        } else {
 9502            completion.into_any_element()
 9503        };
 9504
 9505        let has_completion = self.active_edit_prediction.is_some();
 9506
 9507        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9508        Some(
 9509            h_flex()
 9510                .min_w(min_width)
 9511                .max_w(max_width)
 9512                .flex_1()
 9513                .elevation_2(cx)
 9514                .border_color(cx.theme().colors().border)
 9515                .child(
 9516                    div()
 9517                        .flex_1()
 9518                        .py_1()
 9519                        .px_2()
 9520                        .overflow_hidden()
 9521                        .child(completion),
 9522                )
 9523                .when_some(accept_keystroke, |el, accept_keystroke| {
 9524                    if !accept_keystroke.modifiers().modified() {
 9525                        return el;
 9526                    }
 9527
 9528                    el.child(
 9529                        h_flex()
 9530                            .h_full()
 9531                            .border_l_1()
 9532                            .rounded_r_lg()
 9533                            .border_color(cx.theme().colors().border)
 9534                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9535                            .gap_1()
 9536                            .py_1()
 9537                            .px_2()
 9538                            .child(
 9539                                h_flex()
 9540                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9541                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9542                                    .child(h_flex().children(ui::render_modifiers(
 9543                                        accept_keystroke.modifiers(),
 9544                                        PlatformStyle::platform(),
 9545                                        Some(if !has_completion {
 9546                                            Color::Muted
 9547                                        } else {
 9548                                            Color::Default
 9549                                        }),
 9550                                        None,
 9551                                        false,
 9552                                    ))),
 9553                            )
 9554                            .child(Label::new("Preview").into_any_element())
 9555                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9556                    )
 9557                })
 9558                .into_any(),
 9559        )
 9560    }
 9561
 9562    fn render_edit_prediction_cursor_popover_preview(
 9563        &self,
 9564        completion: &EditPredictionState,
 9565        cursor_point: Point,
 9566        style: &EditorStyle,
 9567        cx: &mut Context<Editor>,
 9568    ) -> Option<Div> {
 9569        use text::ToPoint as _;
 9570
 9571        fn render_relative_row_jump(
 9572            prefix: impl Into<String>,
 9573            current_row: u32,
 9574            target_row: u32,
 9575        ) -> Div {
 9576            let (row_diff, arrow) = if target_row < current_row {
 9577                (current_row - target_row, IconName::ArrowUp)
 9578            } else {
 9579                (target_row - current_row, IconName::ArrowDown)
 9580            };
 9581
 9582            h_flex()
 9583                .child(
 9584                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9585                        .color(Color::Muted)
 9586                        .size(LabelSize::Small),
 9587                )
 9588                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9589        }
 9590
 9591        let supports_jump = self
 9592            .edit_prediction_provider
 9593            .as_ref()
 9594            .map(|provider| provider.provider.supports_jump_to_edit())
 9595            .unwrap_or(true);
 9596
 9597        match &completion.completion {
 9598            EditPrediction::MoveWithin {
 9599                target, snapshot, ..
 9600            } => {
 9601                if !supports_jump {
 9602                    return None;
 9603                }
 9604
 9605                Some(
 9606                    h_flex()
 9607                        .px_2()
 9608                        .gap_2()
 9609                        .flex_1()
 9610                        .child(
 9611                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9612                                Icon::new(IconName::ZedPredictDown)
 9613                            } else {
 9614                                Icon::new(IconName::ZedPredictUp)
 9615                            },
 9616                        )
 9617                        .child(Label::new("Jump to Edit")),
 9618                )
 9619            }
 9620            EditPrediction::MoveOutside { snapshot, .. } => {
 9621                let file_name = snapshot
 9622                    .file()
 9623                    .map(|file| file.file_name(cx))
 9624                    .unwrap_or("untitled");
 9625                Some(
 9626                    h_flex()
 9627                        .px_2()
 9628                        .gap_2()
 9629                        .flex_1()
 9630                        .child(Icon::new(IconName::ZedPredict))
 9631                        .child(Label::new(format!("Jump to {file_name}"))),
 9632                )
 9633            }
 9634            EditPrediction::Edit {
 9635                edits,
 9636                edit_preview,
 9637                snapshot,
 9638                display_mode: _,
 9639            } => {
 9640                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9641
 9642                let (highlighted_edits, has_more_lines) =
 9643                    if let Some(edit_preview) = edit_preview.as_ref() {
 9644                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9645                            .first_line_preview()
 9646                    } else {
 9647                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9648                    };
 9649
 9650                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9651                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9652
 9653                let preview = h_flex()
 9654                    .gap_1()
 9655                    .min_w_16()
 9656                    .child(styled_text)
 9657                    .when(has_more_lines, |parent| parent.child(""));
 9658
 9659                let left = if supports_jump && first_edit_row != cursor_point.row {
 9660                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9661                        .into_any_element()
 9662                } else {
 9663                    let icon_name =
 9664                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9665                    Icon::new(icon_name).into_any_element()
 9666                };
 9667
 9668                Some(
 9669                    h_flex()
 9670                        .h_full()
 9671                        .flex_1()
 9672                        .gap_2()
 9673                        .pr_1()
 9674                        .overflow_x_hidden()
 9675                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9676                        .child(left)
 9677                        .child(preview),
 9678                )
 9679            }
 9680        }
 9681    }
 9682
 9683    pub fn render_context_menu(
 9684        &self,
 9685        style: &EditorStyle,
 9686        max_height_in_lines: u32,
 9687        window: &mut Window,
 9688        cx: &mut Context<Editor>,
 9689    ) -> Option<AnyElement> {
 9690        let menu = self.context_menu.borrow();
 9691        let menu = menu.as_ref()?;
 9692        if !menu.visible() {
 9693            return None;
 9694        };
 9695        Some(menu.render(style, max_height_in_lines, window, cx))
 9696    }
 9697
 9698    fn render_context_menu_aside(
 9699        &mut self,
 9700        max_size: Size<Pixels>,
 9701        window: &mut Window,
 9702        cx: &mut Context<Editor>,
 9703    ) -> Option<AnyElement> {
 9704        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9705            if menu.visible() {
 9706                menu.render_aside(max_size, window, cx)
 9707            } else {
 9708                None
 9709            }
 9710        })
 9711    }
 9712
 9713    fn hide_context_menu(
 9714        &mut self,
 9715        window: &mut Window,
 9716        cx: &mut Context<Self>,
 9717    ) -> Option<CodeContextMenu> {
 9718        cx.notify();
 9719        self.completion_tasks.clear();
 9720        let context_menu = self.context_menu.borrow_mut().take();
 9721        self.stale_edit_prediction_in_menu.take();
 9722        self.update_visible_edit_prediction(window, cx);
 9723        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9724            && let Some(completion_provider) = &self.completion_provider
 9725        {
 9726            completion_provider.selection_changed(None, window, cx);
 9727        }
 9728        context_menu
 9729    }
 9730
 9731    fn show_snippet_choices(
 9732        &mut self,
 9733        choices: &Vec<String>,
 9734        selection: Range<Anchor>,
 9735        cx: &mut Context<Self>,
 9736    ) {
 9737        let Some((_, buffer, _)) = self
 9738            .buffer()
 9739            .read(cx)
 9740            .excerpt_containing(selection.start, cx)
 9741        else {
 9742            return;
 9743        };
 9744        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9745        else {
 9746            return;
 9747        };
 9748        if buffer != end_buffer {
 9749            log::error!("expected anchor range to have matching buffer IDs");
 9750            return;
 9751        }
 9752
 9753        let id = post_inc(&mut self.next_completion_id);
 9754        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9755        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9756            CompletionsMenu::new_snippet_choices(
 9757                id,
 9758                true,
 9759                choices,
 9760                selection,
 9761                buffer,
 9762                snippet_sort_order,
 9763            ),
 9764        ));
 9765    }
 9766
 9767    pub fn insert_snippet(
 9768        &mut self,
 9769        insertion_ranges: &[Range<usize>],
 9770        snippet: Snippet,
 9771        window: &mut Window,
 9772        cx: &mut Context<Self>,
 9773    ) -> Result<()> {
 9774        struct Tabstop<T> {
 9775            is_end_tabstop: bool,
 9776            ranges: Vec<Range<T>>,
 9777            choices: Option<Vec<String>>,
 9778        }
 9779
 9780        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9781            let snippet_text: Arc<str> = snippet.text.clone().into();
 9782            let edits = insertion_ranges
 9783                .iter()
 9784                .cloned()
 9785                .map(|range| (range, snippet_text.clone()));
 9786            let autoindent_mode = AutoindentMode::Block {
 9787                original_indent_columns: Vec::new(),
 9788            };
 9789            buffer.edit(edits, Some(autoindent_mode), cx);
 9790
 9791            let snapshot = &*buffer.read(cx);
 9792            let snippet = &snippet;
 9793            snippet
 9794                .tabstops
 9795                .iter()
 9796                .map(|tabstop| {
 9797                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9798                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9799                    });
 9800                    let mut tabstop_ranges = tabstop
 9801                        .ranges
 9802                        .iter()
 9803                        .flat_map(|tabstop_range| {
 9804                            let mut delta = 0_isize;
 9805                            insertion_ranges.iter().map(move |insertion_range| {
 9806                                let insertion_start = insertion_range.start as isize + delta;
 9807                                delta +=
 9808                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9809
 9810                                let start = ((insertion_start + tabstop_range.start) as usize)
 9811                                    .min(snapshot.len());
 9812                                let end = ((insertion_start + tabstop_range.end) as usize)
 9813                                    .min(snapshot.len());
 9814                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9815                            })
 9816                        })
 9817                        .collect::<Vec<_>>();
 9818                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9819
 9820                    Tabstop {
 9821                        is_end_tabstop,
 9822                        ranges: tabstop_ranges,
 9823                        choices: tabstop.choices.clone(),
 9824                    }
 9825                })
 9826                .collect::<Vec<_>>()
 9827        });
 9828        if let Some(tabstop) = tabstops.first() {
 9829            self.change_selections(Default::default(), window, cx, |s| {
 9830                // Reverse order so that the first range is the newest created selection.
 9831                // Completions will use it and autoscroll will prioritize it.
 9832                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9833            });
 9834
 9835            if let Some(choices) = &tabstop.choices
 9836                && let Some(selection) = tabstop.ranges.first()
 9837            {
 9838                self.show_snippet_choices(choices, selection.clone(), cx)
 9839            }
 9840
 9841            // If we're already at the last tabstop and it's at the end of the snippet,
 9842            // we're done, we don't need to keep the state around.
 9843            if !tabstop.is_end_tabstop {
 9844                let choices = tabstops
 9845                    .iter()
 9846                    .map(|tabstop| tabstop.choices.clone())
 9847                    .collect();
 9848
 9849                let ranges = tabstops
 9850                    .into_iter()
 9851                    .map(|tabstop| tabstop.ranges)
 9852                    .collect::<Vec<_>>();
 9853
 9854                self.snippet_stack.push(SnippetState {
 9855                    active_index: 0,
 9856                    ranges,
 9857                    choices,
 9858                });
 9859            }
 9860
 9861            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9862            if self.autoclose_regions.is_empty() {
 9863                let snapshot = self.buffer.read(cx).snapshot(cx);
 9864                let mut all_selections = self.selections.all::<Point>(cx);
 9865                for selection in &mut all_selections {
 9866                    let selection_head = selection.head();
 9867                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9868                        continue;
 9869                    };
 9870
 9871                    let mut bracket_pair = None;
 9872                    let max_lookup_length = scope
 9873                        .brackets()
 9874                        .map(|(pair, _)| {
 9875                            pair.start
 9876                                .as_str()
 9877                                .chars()
 9878                                .count()
 9879                                .max(pair.end.as_str().chars().count())
 9880                        })
 9881                        .max();
 9882                    if let Some(max_lookup_length) = max_lookup_length {
 9883                        let next_text = snapshot
 9884                            .chars_at(selection_head)
 9885                            .take(max_lookup_length)
 9886                            .collect::<String>();
 9887                        let prev_text = snapshot
 9888                            .reversed_chars_at(selection_head)
 9889                            .take(max_lookup_length)
 9890                            .collect::<String>();
 9891
 9892                        for (pair, enabled) in scope.brackets() {
 9893                            if enabled
 9894                                && pair.close
 9895                                && prev_text.starts_with(pair.start.as_str())
 9896                                && next_text.starts_with(pair.end.as_str())
 9897                            {
 9898                                bracket_pair = Some(pair.clone());
 9899                                break;
 9900                            }
 9901                        }
 9902                    }
 9903
 9904                    if let Some(pair) = bracket_pair {
 9905                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9906                        let autoclose_enabled =
 9907                            self.use_autoclose && snapshot_settings.use_autoclose;
 9908                        if autoclose_enabled {
 9909                            let start = snapshot.anchor_after(selection_head);
 9910                            let end = snapshot.anchor_after(selection_head);
 9911                            self.autoclose_regions.push(AutocloseRegion {
 9912                                selection_id: selection.id,
 9913                                range: start..end,
 9914                                pair,
 9915                            });
 9916                        }
 9917                    }
 9918                }
 9919            }
 9920        }
 9921        Ok(())
 9922    }
 9923
 9924    pub fn move_to_next_snippet_tabstop(
 9925        &mut self,
 9926        window: &mut Window,
 9927        cx: &mut Context<Self>,
 9928    ) -> bool {
 9929        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9930    }
 9931
 9932    pub fn move_to_prev_snippet_tabstop(
 9933        &mut self,
 9934        window: &mut Window,
 9935        cx: &mut Context<Self>,
 9936    ) -> bool {
 9937        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9938    }
 9939
 9940    pub fn move_to_snippet_tabstop(
 9941        &mut self,
 9942        bias: Bias,
 9943        window: &mut Window,
 9944        cx: &mut Context<Self>,
 9945    ) -> bool {
 9946        if let Some(mut snippet) = self.snippet_stack.pop() {
 9947            match bias {
 9948                Bias::Left => {
 9949                    if snippet.active_index > 0 {
 9950                        snippet.active_index -= 1;
 9951                    } else {
 9952                        self.snippet_stack.push(snippet);
 9953                        return false;
 9954                    }
 9955                }
 9956                Bias::Right => {
 9957                    if snippet.active_index + 1 < snippet.ranges.len() {
 9958                        snippet.active_index += 1;
 9959                    } else {
 9960                        self.snippet_stack.push(snippet);
 9961                        return false;
 9962                    }
 9963                }
 9964            }
 9965            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9966                self.change_selections(Default::default(), window, cx, |s| {
 9967                    // Reverse order so that the first range is the newest created selection.
 9968                    // Completions will use it and autoscroll will prioritize it.
 9969                    s.select_ranges(current_ranges.iter().rev().cloned())
 9970                });
 9971
 9972                if let Some(choices) = &snippet.choices[snippet.active_index]
 9973                    && let Some(selection) = current_ranges.first()
 9974                {
 9975                    self.show_snippet_choices(choices, selection.clone(), cx);
 9976                }
 9977
 9978                // If snippet state is not at the last tabstop, push it back on the stack
 9979                if snippet.active_index + 1 < snippet.ranges.len() {
 9980                    self.snippet_stack.push(snippet);
 9981                }
 9982                return true;
 9983            }
 9984        }
 9985
 9986        false
 9987    }
 9988
 9989    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9990        self.transact(window, cx, |this, window, cx| {
 9991            this.select_all(&SelectAll, window, cx);
 9992            this.insert("", window, cx);
 9993        });
 9994    }
 9995
 9996    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9997        if self.read_only(cx) {
 9998            return;
 9999        }
10000        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10001        self.transact(window, cx, |this, window, cx| {
10002            this.select_autoclose_pair(window, cx);
10003            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10004            if !this.linked_edit_ranges.is_empty() {
10005                let selections = this.selections.all::<MultiBufferPoint>(cx);
10006                let snapshot = this.buffer.read(cx).snapshot(cx);
10007
10008                for selection in selections.iter() {
10009                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10010                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10011                    if selection_start.buffer_id != selection_end.buffer_id {
10012                        continue;
10013                    }
10014                    if let Some(ranges) =
10015                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10016                    {
10017                        for (buffer, entries) in ranges {
10018                            linked_ranges.entry(buffer).or_default().extend(entries);
10019                        }
10020                    }
10021                }
10022            }
10023
10024            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10025            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10026            for selection in &mut selections {
10027                if selection.is_empty() {
10028                    let old_head = selection.head();
10029                    let mut new_head =
10030                        movement::left(&display_map, old_head.to_display_point(&display_map))
10031                            .to_point(&display_map);
10032                    if let Some((buffer, line_buffer_range)) = display_map
10033                        .buffer_snapshot()
10034                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10035                    {
10036                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10037                        let indent_len = match indent_size.kind {
10038                            IndentKind::Space => {
10039                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10040                            }
10041                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10042                        };
10043                        if old_head.column <= indent_size.len && old_head.column > 0 {
10044                            let indent_len = indent_len.get();
10045                            new_head = cmp::min(
10046                                new_head,
10047                                MultiBufferPoint::new(
10048                                    old_head.row,
10049                                    ((old_head.column - 1) / indent_len) * indent_len,
10050                                ),
10051                            );
10052                        }
10053                    }
10054
10055                    selection.set_head(new_head, SelectionGoal::None);
10056                }
10057            }
10058
10059            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10060            this.insert("", window, cx);
10061            let empty_str: Arc<str> = Arc::from("");
10062            for (buffer, edits) in linked_ranges {
10063                let snapshot = buffer.read(cx).snapshot();
10064                use text::ToPoint as TP;
10065
10066                let edits = edits
10067                    .into_iter()
10068                    .map(|range| {
10069                        let end_point = TP::to_point(&range.end, &snapshot);
10070                        let mut start_point = TP::to_point(&range.start, &snapshot);
10071
10072                        if end_point == start_point {
10073                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10074                                .saturating_sub(1);
10075                            start_point =
10076                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10077                        };
10078
10079                        (start_point..end_point, empty_str.clone())
10080                    })
10081                    .sorted_by_key(|(range, _)| range.start)
10082                    .collect::<Vec<_>>();
10083                buffer.update(cx, |this, cx| {
10084                    this.edit(edits, None, cx);
10085                })
10086            }
10087            this.refresh_edit_prediction(true, false, window, cx);
10088            refresh_linked_ranges(this, window, cx);
10089        });
10090    }
10091
10092    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10093        if self.read_only(cx) {
10094            return;
10095        }
10096        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10097        self.transact(window, cx, |this, window, cx| {
10098            this.change_selections(Default::default(), window, cx, |s| {
10099                s.move_with(|map, selection| {
10100                    if selection.is_empty() {
10101                        let cursor = movement::right(map, selection.head());
10102                        selection.end = cursor;
10103                        selection.reversed = true;
10104                        selection.goal = SelectionGoal::None;
10105                    }
10106                })
10107            });
10108            this.insert("", window, cx);
10109            this.refresh_edit_prediction(true, false, window, cx);
10110        });
10111    }
10112
10113    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10114        if self.mode.is_single_line() {
10115            cx.propagate();
10116            return;
10117        }
10118
10119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10120        if self.move_to_prev_snippet_tabstop(window, cx) {
10121            return;
10122        }
10123        self.outdent(&Outdent, window, cx);
10124    }
10125
10126    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10127        if self.mode.is_single_line() {
10128            cx.propagate();
10129            return;
10130        }
10131
10132        if self.move_to_next_snippet_tabstop(window, cx) {
10133            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10134            return;
10135        }
10136        if self.read_only(cx) {
10137            return;
10138        }
10139        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10140        let mut selections = self.selections.all_adjusted(cx);
10141        let buffer = self.buffer.read(cx);
10142        let snapshot = buffer.snapshot(cx);
10143        let rows_iter = selections.iter().map(|s| s.head().row);
10144        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10145
10146        let has_some_cursor_in_whitespace = selections
10147            .iter()
10148            .filter(|selection| selection.is_empty())
10149            .any(|selection| {
10150                let cursor = selection.head();
10151                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10152                cursor.column < current_indent.len
10153            });
10154
10155        let mut edits = Vec::new();
10156        let mut prev_edited_row = 0;
10157        let mut row_delta = 0;
10158        for selection in &mut selections {
10159            if selection.start.row != prev_edited_row {
10160                row_delta = 0;
10161            }
10162            prev_edited_row = selection.end.row;
10163
10164            // If the selection is non-empty, then increase the indentation of the selected lines.
10165            if !selection.is_empty() {
10166                row_delta =
10167                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10168                continue;
10169            }
10170
10171            let cursor = selection.head();
10172            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10173            if let Some(suggested_indent) =
10174                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10175            {
10176                // Don't do anything if already at suggested indent
10177                // and there is any other cursor which is not
10178                if has_some_cursor_in_whitespace
10179                    && cursor.column == current_indent.len
10180                    && current_indent.len == suggested_indent.len
10181                {
10182                    continue;
10183                }
10184
10185                // Adjust line and move cursor to suggested indent
10186                // if cursor is not at suggested indent
10187                if cursor.column < suggested_indent.len
10188                    && cursor.column <= current_indent.len
10189                    && current_indent.len <= suggested_indent.len
10190                {
10191                    selection.start = Point::new(cursor.row, suggested_indent.len);
10192                    selection.end = selection.start;
10193                    if row_delta == 0 {
10194                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10195                            cursor.row,
10196                            current_indent,
10197                            suggested_indent,
10198                        ));
10199                        row_delta = suggested_indent.len - current_indent.len;
10200                    }
10201                    continue;
10202                }
10203
10204                // If current indent is more than suggested indent
10205                // only move cursor to current indent and skip indent
10206                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10207                    selection.start = Point::new(cursor.row, current_indent.len);
10208                    selection.end = selection.start;
10209                    continue;
10210                }
10211            }
10212
10213            // Otherwise, insert a hard or soft tab.
10214            let settings = buffer.language_settings_at(cursor, cx);
10215            let tab_size = if settings.hard_tabs {
10216                IndentSize::tab()
10217            } else {
10218                let tab_size = settings.tab_size.get();
10219                let indent_remainder = snapshot
10220                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10221                    .flat_map(str::chars)
10222                    .fold(row_delta % tab_size, |counter: u32, c| {
10223                        if c == '\t' {
10224                            0
10225                        } else {
10226                            (counter + 1) % tab_size
10227                        }
10228                    });
10229
10230                let chars_to_next_tab_stop = tab_size - indent_remainder;
10231                IndentSize::spaces(chars_to_next_tab_stop)
10232            };
10233            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10234            selection.end = selection.start;
10235            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10236            row_delta += tab_size.len;
10237        }
10238
10239        self.transact(window, cx, |this, window, cx| {
10240            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10241            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10242            this.refresh_edit_prediction(true, false, window, cx);
10243        });
10244    }
10245
10246    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10247        if self.read_only(cx) {
10248            return;
10249        }
10250        if self.mode.is_single_line() {
10251            cx.propagate();
10252            return;
10253        }
10254
10255        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10256        let mut selections = self.selections.all::<Point>(cx);
10257        let mut prev_edited_row = 0;
10258        let mut row_delta = 0;
10259        let mut edits = Vec::new();
10260        let buffer = self.buffer.read(cx);
10261        let snapshot = buffer.snapshot(cx);
10262        for selection in &mut selections {
10263            if selection.start.row != prev_edited_row {
10264                row_delta = 0;
10265            }
10266            prev_edited_row = selection.end.row;
10267
10268            row_delta =
10269                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10270        }
10271
10272        self.transact(window, cx, |this, window, cx| {
10273            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10274            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10275        });
10276    }
10277
10278    fn indent_selection(
10279        buffer: &MultiBuffer,
10280        snapshot: &MultiBufferSnapshot,
10281        selection: &mut Selection<Point>,
10282        edits: &mut Vec<(Range<Point>, String)>,
10283        delta_for_start_row: u32,
10284        cx: &App,
10285    ) -> u32 {
10286        let settings = buffer.language_settings_at(selection.start, cx);
10287        let tab_size = settings.tab_size.get();
10288        let indent_kind = if settings.hard_tabs {
10289            IndentKind::Tab
10290        } else {
10291            IndentKind::Space
10292        };
10293        let mut start_row = selection.start.row;
10294        let mut end_row = selection.end.row + 1;
10295
10296        // If a selection ends at the beginning of a line, don't indent
10297        // that last line.
10298        if selection.end.column == 0 && selection.end.row > selection.start.row {
10299            end_row -= 1;
10300        }
10301
10302        // Avoid re-indenting a row that has already been indented by a
10303        // previous selection, but still update this selection's column
10304        // to reflect that indentation.
10305        if delta_for_start_row > 0 {
10306            start_row += 1;
10307            selection.start.column += delta_for_start_row;
10308            if selection.end.row == selection.start.row {
10309                selection.end.column += delta_for_start_row;
10310            }
10311        }
10312
10313        let mut delta_for_end_row = 0;
10314        let has_multiple_rows = start_row + 1 != end_row;
10315        for row in start_row..end_row {
10316            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10317            let indent_delta = match (current_indent.kind, indent_kind) {
10318                (IndentKind::Space, IndentKind::Space) => {
10319                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10320                    IndentSize::spaces(columns_to_next_tab_stop)
10321                }
10322                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10323                (_, IndentKind::Tab) => IndentSize::tab(),
10324            };
10325
10326            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10327                0
10328            } else {
10329                selection.start.column
10330            };
10331            let row_start = Point::new(row, start);
10332            edits.push((
10333                row_start..row_start,
10334                indent_delta.chars().collect::<String>(),
10335            ));
10336
10337            // Update this selection's endpoints to reflect the indentation.
10338            if row == selection.start.row {
10339                selection.start.column += indent_delta.len;
10340            }
10341            if row == selection.end.row {
10342                selection.end.column += indent_delta.len;
10343                delta_for_end_row = indent_delta.len;
10344            }
10345        }
10346
10347        if selection.start.row == selection.end.row {
10348            delta_for_start_row + delta_for_end_row
10349        } else {
10350            delta_for_end_row
10351        }
10352    }
10353
10354    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10355        if self.read_only(cx) {
10356            return;
10357        }
10358        if self.mode.is_single_line() {
10359            cx.propagate();
10360            return;
10361        }
10362
10363        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10364        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10365        let selections = self.selections.all::<Point>(cx);
10366        let mut deletion_ranges = Vec::new();
10367        let mut last_outdent = None;
10368        {
10369            let buffer = self.buffer.read(cx);
10370            let snapshot = buffer.snapshot(cx);
10371            for selection in &selections {
10372                let settings = buffer.language_settings_at(selection.start, cx);
10373                let tab_size = settings.tab_size.get();
10374                let mut rows = selection.spanned_rows(false, &display_map);
10375
10376                // Avoid re-outdenting a row that has already been outdented by a
10377                // previous selection.
10378                if let Some(last_row) = last_outdent
10379                    && last_row == rows.start
10380                {
10381                    rows.start = rows.start.next_row();
10382                }
10383                let has_multiple_rows = rows.len() > 1;
10384                for row in rows.iter_rows() {
10385                    let indent_size = snapshot.indent_size_for_line(row);
10386                    if indent_size.len > 0 {
10387                        let deletion_len = match indent_size.kind {
10388                            IndentKind::Space => {
10389                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10390                                if columns_to_prev_tab_stop == 0 {
10391                                    tab_size
10392                                } else {
10393                                    columns_to_prev_tab_stop
10394                                }
10395                            }
10396                            IndentKind::Tab => 1,
10397                        };
10398                        let start = if has_multiple_rows
10399                            || deletion_len > selection.start.column
10400                            || indent_size.len < selection.start.column
10401                        {
10402                            0
10403                        } else {
10404                            selection.start.column - deletion_len
10405                        };
10406                        deletion_ranges.push(
10407                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10408                        );
10409                        last_outdent = Some(row);
10410                    }
10411                }
10412            }
10413        }
10414
10415        self.transact(window, cx, |this, window, cx| {
10416            this.buffer.update(cx, |buffer, cx| {
10417                let empty_str: Arc<str> = Arc::default();
10418                buffer.edit(
10419                    deletion_ranges
10420                        .into_iter()
10421                        .map(|range| (range, empty_str.clone())),
10422                    None,
10423                    cx,
10424                );
10425            });
10426            let selections = this.selections.all::<usize>(cx);
10427            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10428        });
10429    }
10430
10431    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10432        if self.read_only(cx) {
10433            return;
10434        }
10435        if self.mode.is_single_line() {
10436            cx.propagate();
10437            return;
10438        }
10439
10440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10441        let selections = self
10442            .selections
10443            .all::<usize>(cx)
10444            .into_iter()
10445            .map(|s| s.range());
10446
10447        self.transact(window, cx, |this, window, cx| {
10448            this.buffer.update(cx, |buffer, cx| {
10449                buffer.autoindent_ranges(selections, cx);
10450            });
10451            let selections = this.selections.all::<usize>(cx);
10452            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10453        });
10454    }
10455
10456    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10458        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10459        let selections = self.selections.all::<Point>(cx);
10460
10461        let mut new_cursors = Vec::new();
10462        let mut edit_ranges = Vec::new();
10463        let mut selections = selections.iter().peekable();
10464        while let Some(selection) = selections.next() {
10465            let mut rows = selection.spanned_rows(false, &display_map);
10466
10467            // Accumulate contiguous regions of rows that we want to delete.
10468            while let Some(next_selection) = selections.peek() {
10469                let next_rows = next_selection.spanned_rows(false, &display_map);
10470                if next_rows.start <= rows.end {
10471                    rows.end = next_rows.end;
10472                    selections.next().unwrap();
10473                } else {
10474                    break;
10475                }
10476            }
10477
10478            let buffer = display_map.buffer_snapshot();
10479            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10480            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10481                // If there's a line after the range, delete the \n from the end of the row range
10482                (
10483                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10484                    rows.end,
10485                )
10486            } else {
10487                // If there isn't a line after the range, delete the \n from the line before the
10488                // start of the row range
10489                edit_start = edit_start.saturating_sub(1);
10490                (buffer.len(), rows.start.previous_row())
10491            };
10492
10493            let text_layout_details = self.text_layout_details(window);
10494            let x = display_map.x_for_display_point(
10495                selection.head().to_display_point(&display_map),
10496                &text_layout_details,
10497            );
10498            let row = Point::new(target_row.0, 0)
10499                .to_display_point(&display_map)
10500                .row();
10501            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10502
10503            new_cursors.push((
10504                selection.id,
10505                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10506                SelectionGoal::None,
10507            ));
10508            edit_ranges.push(edit_start..edit_end);
10509        }
10510
10511        self.transact(window, cx, |this, window, cx| {
10512            let buffer = this.buffer.update(cx, |buffer, cx| {
10513                let empty_str: Arc<str> = Arc::default();
10514                buffer.edit(
10515                    edit_ranges
10516                        .into_iter()
10517                        .map(|range| (range, empty_str.clone())),
10518                    None,
10519                    cx,
10520                );
10521                buffer.snapshot(cx)
10522            });
10523            let new_selections = new_cursors
10524                .into_iter()
10525                .map(|(id, cursor, goal)| {
10526                    let cursor = cursor.to_point(&buffer);
10527                    Selection {
10528                        id,
10529                        start: cursor,
10530                        end: cursor,
10531                        reversed: false,
10532                        goal,
10533                    }
10534                })
10535                .collect();
10536
10537            this.change_selections(Default::default(), window, cx, |s| {
10538                s.select(new_selections);
10539            });
10540        });
10541    }
10542
10543    pub fn join_lines_impl(
10544        &mut self,
10545        insert_whitespace: bool,
10546        window: &mut Window,
10547        cx: &mut Context<Self>,
10548    ) {
10549        if self.read_only(cx) {
10550            return;
10551        }
10552        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10553        for selection in self.selections.all::<Point>(cx) {
10554            let start = MultiBufferRow(selection.start.row);
10555            // Treat single line selections as if they include the next line. Otherwise this action
10556            // would do nothing for single line selections individual cursors.
10557            let end = if selection.start.row == selection.end.row {
10558                MultiBufferRow(selection.start.row + 1)
10559            } else {
10560                MultiBufferRow(selection.end.row)
10561            };
10562
10563            if let Some(last_row_range) = row_ranges.last_mut()
10564                && start <= last_row_range.end
10565            {
10566                last_row_range.end = end;
10567                continue;
10568            }
10569            row_ranges.push(start..end);
10570        }
10571
10572        let snapshot = self.buffer.read(cx).snapshot(cx);
10573        let mut cursor_positions = Vec::new();
10574        for row_range in &row_ranges {
10575            let anchor = snapshot.anchor_before(Point::new(
10576                row_range.end.previous_row().0,
10577                snapshot.line_len(row_range.end.previous_row()),
10578            ));
10579            cursor_positions.push(anchor..anchor);
10580        }
10581
10582        self.transact(window, cx, |this, window, cx| {
10583            for row_range in row_ranges.into_iter().rev() {
10584                for row in row_range.iter_rows().rev() {
10585                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10586                    let next_line_row = row.next_row();
10587                    let indent = snapshot.indent_size_for_line(next_line_row);
10588                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10589
10590                    let replace =
10591                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10592                            " "
10593                        } else {
10594                            ""
10595                        };
10596
10597                    this.buffer.update(cx, |buffer, cx| {
10598                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10599                    });
10600                }
10601            }
10602
10603            this.change_selections(Default::default(), window, cx, |s| {
10604                s.select_anchor_ranges(cursor_positions)
10605            });
10606        });
10607    }
10608
10609    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10611        self.join_lines_impl(true, window, cx);
10612    }
10613
10614    pub fn sort_lines_case_sensitive(
10615        &mut self,
10616        _: &SortLinesCaseSensitive,
10617        window: &mut Window,
10618        cx: &mut Context<Self>,
10619    ) {
10620        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10621    }
10622
10623    pub fn sort_lines_by_length(
10624        &mut self,
10625        _: &SortLinesByLength,
10626        window: &mut Window,
10627        cx: &mut Context<Self>,
10628    ) {
10629        self.manipulate_immutable_lines(window, cx, |lines| {
10630            lines.sort_by_key(|&line| line.chars().count())
10631        })
10632    }
10633
10634    pub fn sort_lines_case_insensitive(
10635        &mut self,
10636        _: &SortLinesCaseInsensitive,
10637        window: &mut Window,
10638        cx: &mut Context<Self>,
10639    ) {
10640        self.manipulate_immutable_lines(window, cx, |lines| {
10641            lines.sort_by_key(|line| line.to_lowercase())
10642        })
10643    }
10644
10645    pub fn unique_lines_case_insensitive(
10646        &mut self,
10647        _: &UniqueLinesCaseInsensitive,
10648        window: &mut Window,
10649        cx: &mut Context<Self>,
10650    ) {
10651        self.manipulate_immutable_lines(window, cx, |lines| {
10652            let mut seen = HashSet::default();
10653            lines.retain(|line| seen.insert(line.to_lowercase()));
10654        })
10655    }
10656
10657    pub fn unique_lines_case_sensitive(
10658        &mut self,
10659        _: &UniqueLinesCaseSensitive,
10660        window: &mut Window,
10661        cx: &mut Context<Self>,
10662    ) {
10663        self.manipulate_immutable_lines(window, cx, |lines| {
10664            let mut seen = HashSet::default();
10665            lines.retain(|line| seen.insert(*line));
10666        })
10667    }
10668
10669    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10670        let snapshot = self.buffer.read(cx).snapshot(cx);
10671        for selection in self.selections.disjoint_anchors_arc().iter() {
10672            if snapshot
10673                .language_at(selection.start)
10674                .and_then(|lang| lang.config().wrap_characters.as_ref())
10675                .is_some()
10676            {
10677                return true;
10678            }
10679        }
10680        false
10681    }
10682
10683    fn wrap_selections_in_tag(
10684        &mut self,
10685        _: &WrapSelectionsInTag,
10686        window: &mut Window,
10687        cx: &mut Context<Self>,
10688    ) {
10689        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10690
10691        let snapshot = self.buffer.read(cx).snapshot(cx);
10692
10693        let mut edits = Vec::new();
10694        let mut boundaries = Vec::new();
10695
10696        for selection in self.selections.all::<Point>(cx).iter() {
10697            let Some(wrap_config) = snapshot
10698                .language_at(selection.start)
10699                .and_then(|lang| lang.config().wrap_characters.clone())
10700            else {
10701                continue;
10702            };
10703
10704            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10705            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10706
10707            let start_before = snapshot.anchor_before(selection.start);
10708            let end_after = snapshot.anchor_after(selection.end);
10709
10710            edits.push((start_before..start_before, open_tag));
10711            edits.push((end_after..end_after, close_tag));
10712
10713            boundaries.push((
10714                start_before,
10715                end_after,
10716                wrap_config.start_prefix.len(),
10717                wrap_config.end_suffix.len(),
10718            ));
10719        }
10720
10721        if edits.is_empty() {
10722            return;
10723        }
10724
10725        self.transact(window, cx, |this, window, cx| {
10726            let buffer = this.buffer.update(cx, |buffer, cx| {
10727                buffer.edit(edits, None, cx);
10728                buffer.snapshot(cx)
10729            });
10730
10731            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10732            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10733                boundaries.into_iter()
10734            {
10735                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10736                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10737                new_selections.push(open_offset..open_offset);
10738                new_selections.push(close_offset..close_offset);
10739            }
10740
10741            this.change_selections(Default::default(), window, cx, |s| {
10742                s.select_ranges(new_selections);
10743            });
10744
10745            this.request_autoscroll(Autoscroll::fit(), cx);
10746        });
10747    }
10748
10749    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10750        let Some(project) = self.project.clone() else {
10751            return;
10752        };
10753        self.reload(project, window, cx)
10754            .detach_and_notify_err(window, cx);
10755    }
10756
10757    pub fn restore_file(
10758        &mut self,
10759        _: &::git::RestoreFile,
10760        window: &mut Window,
10761        cx: &mut Context<Self>,
10762    ) {
10763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10764        let mut buffer_ids = HashSet::default();
10765        let snapshot = self.buffer().read(cx).snapshot(cx);
10766        for selection in self.selections.all::<usize>(cx) {
10767            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10768        }
10769
10770        let buffer = self.buffer().read(cx);
10771        let ranges = buffer_ids
10772            .into_iter()
10773            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10774            .collect::<Vec<_>>();
10775
10776        self.restore_hunks_in_ranges(ranges, window, cx);
10777    }
10778
10779    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10781        let selections = self
10782            .selections
10783            .all(cx)
10784            .into_iter()
10785            .map(|s| s.range())
10786            .collect();
10787        self.restore_hunks_in_ranges(selections, window, cx);
10788    }
10789
10790    pub fn restore_hunks_in_ranges(
10791        &mut self,
10792        ranges: Vec<Range<Point>>,
10793        window: &mut Window,
10794        cx: &mut Context<Editor>,
10795    ) {
10796        let mut revert_changes = HashMap::default();
10797        let chunk_by = self
10798            .snapshot(window, cx)
10799            .hunks_for_ranges(ranges)
10800            .into_iter()
10801            .chunk_by(|hunk| hunk.buffer_id);
10802        for (buffer_id, hunks) in &chunk_by {
10803            let hunks = hunks.collect::<Vec<_>>();
10804            for hunk in &hunks {
10805                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10806            }
10807            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10808        }
10809        drop(chunk_by);
10810        if !revert_changes.is_empty() {
10811            self.transact(window, cx, |editor, window, cx| {
10812                editor.restore(revert_changes, window, cx);
10813            });
10814        }
10815    }
10816
10817    pub fn open_active_item_in_terminal(
10818        &mut self,
10819        _: &OpenInTerminal,
10820        window: &mut Window,
10821        cx: &mut Context<Self>,
10822    ) {
10823        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10824            let project_path = buffer.read(cx).project_path(cx)?;
10825            let project = self.project()?.read(cx);
10826            let entry = project.entry_for_path(&project_path, cx)?;
10827            let parent = match &entry.canonical_path {
10828                Some(canonical_path) => canonical_path.to_path_buf(),
10829                None => project.absolute_path(&project_path, cx)?,
10830            }
10831            .parent()?
10832            .to_path_buf();
10833            Some(parent)
10834        }) {
10835            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10836        }
10837    }
10838
10839    fn set_breakpoint_context_menu(
10840        &mut self,
10841        display_row: DisplayRow,
10842        position: Option<Anchor>,
10843        clicked_point: gpui::Point<Pixels>,
10844        window: &mut Window,
10845        cx: &mut Context<Self>,
10846    ) {
10847        let source = self
10848            .buffer
10849            .read(cx)
10850            .snapshot(cx)
10851            .anchor_before(Point::new(display_row.0, 0u32));
10852
10853        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10854
10855        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10856            self,
10857            source,
10858            clicked_point,
10859            context_menu,
10860            window,
10861            cx,
10862        );
10863    }
10864
10865    fn add_edit_breakpoint_block(
10866        &mut self,
10867        anchor: Anchor,
10868        breakpoint: &Breakpoint,
10869        edit_action: BreakpointPromptEditAction,
10870        window: &mut Window,
10871        cx: &mut Context<Self>,
10872    ) {
10873        let weak_editor = cx.weak_entity();
10874        let bp_prompt = cx.new(|cx| {
10875            BreakpointPromptEditor::new(
10876                weak_editor,
10877                anchor,
10878                breakpoint.clone(),
10879                edit_action,
10880                window,
10881                cx,
10882            )
10883        });
10884
10885        let height = bp_prompt.update(cx, |this, cx| {
10886            this.prompt
10887                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10888        });
10889        let cloned_prompt = bp_prompt.clone();
10890        let blocks = vec![BlockProperties {
10891            style: BlockStyle::Sticky,
10892            placement: BlockPlacement::Above(anchor),
10893            height: Some(height),
10894            render: Arc::new(move |cx| {
10895                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10896                cloned_prompt.clone().into_any_element()
10897            }),
10898            priority: 0,
10899        }];
10900
10901        let focus_handle = bp_prompt.focus_handle(cx);
10902        window.focus(&focus_handle);
10903
10904        let block_ids = self.insert_blocks(blocks, None, cx);
10905        bp_prompt.update(cx, |prompt, _| {
10906            prompt.add_block_ids(block_ids);
10907        });
10908    }
10909
10910    pub(crate) fn breakpoint_at_row(
10911        &self,
10912        row: u32,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) -> Option<(Anchor, Breakpoint)> {
10916        let snapshot = self.snapshot(window, cx);
10917        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10918
10919        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10920    }
10921
10922    pub(crate) fn breakpoint_at_anchor(
10923        &self,
10924        breakpoint_position: Anchor,
10925        snapshot: &EditorSnapshot,
10926        cx: &mut Context<Self>,
10927    ) -> Option<(Anchor, Breakpoint)> {
10928        let buffer = self
10929            .buffer
10930            .read(cx)
10931            .buffer_for_anchor(breakpoint_position, cx)?;
10932
10933        let enclosing_excerpt = breakpoint_position.excerpt_id;
10934        let buffer_snapshot = buffer.read(cx).snapshot();
10935
10936        let row = buffer_snapshot
10937            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10938            .row;
10939
10940        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10941        let anchor_end = snapshot
10942            .buffer_snapshot()
10943            .anchor_after(Point::new(row, line_len));
10944
10945        self.breakpoint_store
10946            .as_ref()?
10947            .read_with(cx, |breakpoint_store, cx| {
10948                breakpoint_store
10949                    .breakpoints(
10950                        &buffer,
10951                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10952                        &buffer_snapshot,
10953                        cx,
10954                    )
10955                    .next()
10956                    .and_then(|(bp, _)| {
10957                        let breakpoint_row = buffer_snapshot
10958                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10959                            .row;
10960
10961                        if breakpoint_row == row {
10962                            snapshot
10963                                .buffer_snapshot()
10964                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10965                                .map(|position| (position, bp.bp.clone()))
10966                        } else {
10967                            None
10968                        }
10969                    })
10970            })
10971    }
10972
10973    pub fn edit_log_breakpoint(
10974        &mut self,
10975        _: &EditLogBreakpoint,
10976        window: &mut Window,
10977        cx: &mut Context<Self>,
10978    ) {
10979        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10980            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10981                message: None,
10982                state: BreakpointState::Enabled,
10983                condition: None,
10984                hit_condition: None,
10985            });
10986
10987            self.add_edit_breakpoint_block(
10988                anchor,
10989                &breakpoint,
10990                BreakpointPromptEditAction::Log,
10991                window,
10992                cx,
10993            );
10994        }
10995    }
10996
10997    fn breakpoints_at_cursors(
10998        &self,
10999        window: &mut Window,
11000        cx: &mut Context<Self>,
11001    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11002        let snapshot = self.snapshot(window, cx);
11003        let cursors = self
11004            .selections
11005            .disjoint_anchors_arc()
11006            .iter()
11007            .map(|selection| {
11008                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11009
11010                let breakpoint_position = self
11011                    .breakpoint_at_row(cursor_position.row, window, cx)
11012                    .map(|bp| bp.0)
11013                    .unwrap_or_else(|| {
11014                        snapshot
11015                            .display_snapshot
11016                            .buffer_snapshot()
11017                            .anchor_after(Point::new(cursor_position.row, 0))
11018                    });
11019
11020                let breakpoint = self
11021                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11022                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11023
11024                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11025            })
11026            // 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.
11027            .collect::<HashMap<Anchor, _>>();
11028
11029        cursors.into_iter().collect()
11030    }
11031
11032    pub fn enable_breakpoint(
11033        &mut self,
11034        _: &crate::actions::EnableBreakpoint,
11035        window: &mut Window,
11036        cx: &mut Context<Self>,
11037    ) {
11038        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11039            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11040                continue;
11041            };
11042            self.edit_breakpoint_at_anchor(
11043                anchor,
11044                breakpoint,
11045                BreakpointEditAction::InvertState,
11046                cx,
11047            );
11048        }
11049    }
11050
11051    pub fn disable_breakpoint(
11052        &mut self,
11053        _: &crate::actions::DisableBreakpoint,
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_enabled()) 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 toggle_breakpoint(
11071        &mut self,
11072        _: &crate::actions::ToggleBreakpoint,
11073        window: &mut Window,
11074        cx: &mut Context<Self>,
11075    ) {
11076        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11077            if let Some(breakpoint) = breakpoint {
11078                self.edit_breakpoint_at_anchor(
11079                    anchor,
11080                    breakpoint,
11081                    BreakpointEditAction::Toggle,
11082                    cx,
11083                );
11084            } else {
11085                self.edit_breakpoint_at_anchor(
11086                    anchor,
11087                    Breakpoint::new_standard(),
11088                    BreakpointEditAction::Toggle,
11089                    cx,
11090                );
11091            }
11092        }
11093    }
11094
11095    pub fn edit_breakpoint_at_anchor(
11096        &mut self,
11097        breakpoint_position: Anchor,
11098        breakpoint: Breakpoint,
11099        edit_action: BreakpointEditAction,
11100        cx: &mut Context<Self>,
11101    ) {
11102        let Some(breakpoint_store) = &self.breakpoint_store else {
11103            return;
11104        };
11105
11106        let Some(buffer) = self
11107            .buffer
11108            .read(cx)
11109            .buffer_for_anchor(breakpoint_position, cx)
11110        else {
11111            return;
11112        };
11113
11114        breakpoint_store.update(cx, |breakpoint_store, cx| {
11115            breakpoint_store.toggle_breakpoint(
11116                buffer,
11117                BreakpointWithPosition {
11118                    position: breakpoint_position.text_anchor,
11119                    bp: breakpoint,
11120                },
11121                edit_action,
11122                cx,
11123            );
11124        });
11125
11126        cx.notify();
11127    }
11128
11129    #[cfg(any(test, feature = "test-support"))]
11130    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11131        self.breakpoint_store.clone()
11132    }
11133
11134    pub fn prepare_restore_change(
11135        &self,
11136        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11137        hunk: &MultiBufferDiffHunk,
11138        cx: &mut App,
11139    ) -> Option<()> {
11140        if hunk.is_created_file() {
11141            return None;
11142        }
11143        let buffer = self.buffer.read(cx);
11144        let diff = buffer.diff_for(hunk.buffer_id)?;
11145        let buffer = buffer.buffer(hunk.buffer_id)?;
11146        let buffer = buffer.read(cx);
11147        let original_text = diff
11148            .read(cx)
11149            .base_text()
11150            .as_rope()
11151            .slice(hunk.diff_base_byte_range.clone());
11152        let buffer_snapshot = buffer.snapshot();
11153        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11154        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11155            probe
11156                .0
11157                .start
11158                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11159                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11160        }) {
11161            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11162            Some(())
11163        } else {
11164            None
11165        }
11166    }
11167
11168    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11169        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11170    }
11171
11172    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11173        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11174    }
11175
11176    fn manipulate_lines<M>(
11177        &mut self,
11178        window: &mut Window,
11179        cx: &mut Context<Self>,
11180        mut manipulate: M,
11181    ) where
11182        M: FnMut(&str) -> LineManipulationResult,
11183    {
11184        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11185
11186        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11187        let buffer = self.buffer.read(cx).snapshot(cx);
11188
11189        let mut edits = Vec::new();
11190
11191        let selections = self.selections.all::<Point>(cx);
11192        let mut selections = selections.iter().peekable();
11193        let mut contiguous_row_selections = Vec::new();
11194        let mut new_selections = Vec::new();
11195        let mut added_lines = 0;
11196        let mut removed_lines = 0;
11197
11198        while let Some(selection) = selections.next() {
11199            let (start_row, end_row) = consume_contiguous_rows(
11200                &mut contiguous_row_selections,
11201                selection,
11202                &display_map,
11203                &mut selections,
11204            );
11205
11206            let start_point = Point::new(start_row.0, 0);
11207            let end_point = Point::new(
11208                end_row.previous_row().0,
11209                buffer.line_len(end_row.previous_row()),
11210            );
11211            let text = buffer
11212                .text_for_range(start_point..end_point)
11213                .collect::<String>();
11214
11215            let LineManipulationResult {
11216                new_text,
11217                line_count_before,
11218                line_count_after,
11219            } = manipulate(&text);
11220
11221            edits.push((start_point..end_point, new_text));
11222
11223            // Selections must change based on added and removed line count
11224            let start_row =
11225                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11226            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11227            new_selections.push(Selection {
11228                id: selection.id,
11229                start: start_row,
11230                end: end_row,
11231                goal: SelectionGoal::None,
11232                reversed: selection.reversed,
11233            });
11234
11235            if line_count_after > line_count_before {
11236                added_lines += line_count_after - line_count_before;
11237            } else if line_count_before > line_count_after {
11238                removed_lines += line_count_before - line_count_after;
11239            }
11240        }
11241
11242        self.transact(window, cx, |this, window, cx| {
11243            let buffer = this.buffer.update(cx, |buffer, cx| {
11244                buffer.edit(edits, None, cx);
11245                buffer.snapshot(cx)
11246            });
11247
11248            // Recalculate offsets on newly edited buffer
11249            let new_selections = new_selections
11250                .iter()
11251                .map(|s| {
11252                    let start_point = Point::new(s.start.0, 0);
11253                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11254                    Selection {
11255                        id: s.id,
11256                        start: buffer.point_to_offset(start_point),
11257                        end: buffer.point_to_offset(end_point),
11258                        goal: s.goal,
11259                        reversed: s.reversed,
11260                    }
11261                })
11262                .collect();
11263
11264            this.change_selections(Default::default(), window, cx, |s| {
11265                s.select(new_selections);
11266            });
11267
11268            this.request_autoscroll(Autoscroll::fit(), cx);
11269        });
11270    }
11271
11272    fn manipulate_immutable_lines<Fn>(
11273        &mut self,
11274        window: &mut Window,
11275        cx: &mut Context<Self>,
11276        mut callback: Fn,
11277    ) where
11278        Fn: FnMut(&mut Vec<&str>),
11279    {
11280        self.manipulate_lines(window, cx, |text| {
11281            let mut lines: Vec<&str> = text.split('\n').collect();
11282            let line_count_before = lines.len();
11283
11284            callback(&mut lines);
11285
11286            LineManipulationResult {
11287                new_text: lines.join("\n"),
11288                line_count_before,
11289                line_count_after: lines.len(),
11290            }
11291        });
11292    }
11293
11294    fn manipulate_mutable_lines<Fn>(
11295        &mut self,
11296        window: &mut Window,
11297        cx: &mut Context<Self>,
11298        mut callback: Fn,
11299    ) where
11300        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11301    {
11302        self.manipulate_lines(window, cx, |text| {
11303            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11304            let line_count_before = lines.len();
11305
11306            callback(&mut lines);
11307
11308            LineManipulationResult {
11309                new_text: lines.join("\n"),
11310                line_count_before,
11311                line_count_after: lines.len(),
11312            }
11313        });
11314    }
11315
11316    pub fn convert_indentation_to_spaces(
11317        &mut self,
11318        _: &ConvertIndentationToSpaces,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        let settings = self.buffer.read(cx).language_settings(cx);
11323        let tab_size = settings.tab_size.get() as usize;
11324
11325        self.manipulate_mutable_lines(window, cx, |lines| {
11326            // Allocates a reasonably sized scratch buffer once for the whole loop
11327            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11328            // Avoids recomputing spaces that could be inserted many times
11329            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11330                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11331                .collect();
11332
11333            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11334                let mut chars = line.as_ref().chars();
11335                let mut col = 0;
11336                let mut changed = false;
11337
11338                for ch in chars.by_ref() {
11339                    match ch {
11340                        ' ' => {
11341                            reindented_line.push(' ');
11342                            col += 1;
11343                        }
11344                        '\t' => {
11345                            // \t are converted to spaces depending on the current column
11346                            let spaces_len = tab_size - (col % tab_size);
11347                            reindented_line.extend(&space_cache[spaces_len - 1]);
11348                            col += spaces_len;
11349                            changed = true;
11350                        }
11351                        _ => {
11352                            // If we dont append before break, the character is consumed
11353                            reindented_line.push(ch);
11354                            break;
11355                        }
11356                    }
11357                }
11358
11359                if !changed {
11360                    reindented_line.clear();
11361                    continue;
11362                }
11363                // Append the rest of the line and replace old reference with new one
11364                reindented_line.extend(chars);
11365                *line = Cow::Owned(reindented_line.clone());
11366                reindented_line.clear();
11367            }
11368        });
11369    }
11370
11371    pub fn convert_indentation_to_tabs(
11372        &mut self,
11373        _: &ConvertIndentationToTabs,
11374        window: &mut Window,
11375        cx: &mut Context<Self>,
11376    ) {
11377        let settings = self.buffer.read(cx).language_settings(cx);
11378        let tab_size = settings.tab_size.get() as usize;
11379
11380        self.manipulate_mutable_lines(window, cx, |lines| {
11381            // Allocates a reasonably sized buffer once for the whole loop
11382            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11383            // Avoids recomputing spaces that could be inserted many times
11384            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11385                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11386                .collect();
11387
11388            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11389                let mut chars = line.chars();
11390                let mut spaces_count = 0;
11391                let mut first_non_indent_char = None;
11392                let mut changed = false;
11393
11394                for ch in chars.by_ref() {
11395                    match ch {
11396                        ' ' => {
11397                            // Keep track of spaces. Append \t when we reach tab_size
11398                            spaces_count += 1;
11399                            changed = true;
11400                            if spaces_count == tab_size {
11401                                reindented_line.push('\t');
11402                                spaces_count = 0;
11403                            }
11404                        }
11405                        '\t' => {
11406                            reindented_line.push('\t');
11407                            spaces_count = 0;
11408                        }
11409                        _ => {
11410                            // Dont append it yet, we might have remaining spaces
11411                            first_non_indent_char = Some(ch);
11412                            break;
11413                        }
11414                    }
11415                }
11416
11417                if !changed {
11418                    reindented_line.clear();
11419                    continue;
11420                }
11421                // Remaining spaces that didn't make a full tab stop
11422                if spaces_count > 0 {
11423                    reindented_line.extend(&space_cache[spaces_count - 1]);
11424                }
11425                // If we consume an extra character that was not indentation, add it back
11426                if let Some(extra_char) = first_non_indent_char {
11427                    reindented_line.push(extra_char);
11428                }
11429                // Append the rest of the line and replace old reference with new one
11430                reindented_line.extend(chars);
11431                *line = Cow::Owned(reindented_line.clone());
11432                reindented_line.clear();
11433            }
11434        });
11435    }
11436
11437    pub fn convert_to_upper_case(
11438        &mut self,
11439        _: &ConvertToUpperCase,
11440        window: &mut Window,
11441        cx: &mut Context<Self>,
11442    ) {
11443        self.manipulate_text(window, cx, |text| text.to_uppercase())
11444    }
11445
11446    pub fn convert_to_lower_case(
11447        &mut self,
11448        _: &ConvertToLowerCase,
11449        window: &mut Window,
11450        cx: &mut Context<Self>,
11451    ) {
11452        self.manipulate_text(window, cx, |text| text.to_lowercase())
11453    }
11454
11455    pub fn convert_to_title_case(
11456        &mut self,
11457        _: &ConvertToTitleCase,
11458        window: &mut Window,
11459        cx: &mut Context<Self>,
11460    ) {
11461        self.manipulate_text(window, cx, |text| {
11462            text.split('\n')
11463                .map(|line| line.to_case(Case::Title))
11464                .join("\n")
11465        })
11466    }
11467
11468    pub fn convert_to_snake_case(
11469        &mut self,
11470        _: &ConvertToSnakeCase,
11471        window: &mut Window,
11472        cx: &mut Context<Self>,
11473    ) {
11474        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11475    }
11476
11477    pub fn convert_to_kebab_case(
11478        &mut self,
11479        _: &ConvertToKebabCase,
11480        window: &mut Window,
11481        cx: &mut Context<Self>,
11482    ) {
11483        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11484    }
11485
11486    pub fn convert_to_upper_camel_case(
11487        &mut self,
11488        _: &ConvertToUpperCamelCase,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        self.manipulate_text(window, cx, |text| {
11493            text.split('\n')
11494                .map(|line| line.to_case(Case::UpperCamel))
11495                .join("\n")
11496        })
11497    }
11498
11499    pub fn convert_to_lower_camel_case(
11500        &mut self,
11501        _: &ConvertToLowerCamelCase,
11502        window: &mut Window,
11503        cx: &mut Context<Self>,
11504    ) {
11505        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11506    }
11507
11508    pub fn convert_to_opposite_case(
11509        &mut self,
11510        _: &ConvertToOppositeCase,
11511        window: &mut Window,
11512        cx: &mut Context<Self>,
11513    ) {
11514        self.manipulate_text(window, cx, |text| {
11515            text.chars()
11516                .fold(String::with_capacity(text.len()), |mut t, c| {
11517                    if c.is_uppercase() {
11518                        t.extend(c.to_lowercase());
11519                    } else {
11520                        t.extend(c.to_uppercase());
11521                    }
11522                    t
11523                })
11524        })
11525    }
11526
11527    pub fn convert_to_sentence_case(
11528        &mut self,
11529        _: &ConvertToSentenceCase,
11530        window: &mut Window,
11531        cx: &mut Context<Self>,
11532    ) {
11533        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11534    }
11535
11536    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11537        self.manipulate_text(window, cx, |text| {
11538            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11539            if has_upper_case_characters {
11540                text.to_lowercase()
11541            } else {
11542                text.to_uppercase()
11543            }
11544        })
11545    }
11546
11547    pub fn convert_to_rot13(
11548        &mut self,
11549        _: &ConvertToRot13,
11550        window: &mut Window,
11551        cx: &mut Context<Self>,
11552    ) {
11553        self.manipulate_text(window, cx, |text| {
11554            text.chars()
11555                .map(|c| match c {
11556                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11557                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11558                    _ => c,
11559                })
11560                .collect()
11561        })
11562    }
11563
11564    pub fn convert_to_rot47(
11565        &mut self,
11566        _: &ConvertToRot47,
11567        window: &mut Window,
11568        cx: &mut Context<Self>,
11569    ) {
11570        self.manipulate_text(window, cx, |text| {
11571            text.chars()
11572                .map(|c| {
11573                    let code_point = c as u32;
11574                    if code_point >= 33 && code_point <= 126 {
11575                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11576                    }
11577                    c
11578                })
11579                .collect()
11580        })
11581    }
11582
11583    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11584    where
11585        Fn: FnMut(&str) -> String,
11586    {
11587        let buffer = self.buffer.read(cx).snapshot(cx);
11588
11589        let mut new_selections = Vec::new();
11590        let mut edits = Vec::new();
11591        let mut selection_adjustment = 0i32;
11592
11593        for selection in self.selections.all_adjusted(cx) {
11594            let selection_is_empty = selection.is_empty();
11595
11596            let (start, end) = if selection_is_empty {
11597                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11598                (word_range.start, word_range.end)
11599            } else {
11600                (
11601                    buffer.point_to_offset(selection.start),
11602                    buffer.point_to_offset(selection.end),
11603                )
11604            };
11605
11606            let text = buffer.text_for_range(start..end).collect::<String>();
11607            let old_length = text.len() as i32;
11608            let text = callback(&text);
11609
11610            new_selections.push(Selection {
11611                start: (start as i32 - selection_adjustment) as usize,
11612                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11613                goal: SelectionGoal::None,
11614                id: selection.id,
11615                reversed: selection.reversed,
11616            });
11617
11618            selection_adjustment += old_length - text.len() as i32;
11619
11620            edits.push((start..end, text));
11621        }
11622
11623        self.transact(window, cx, |this, window, cx| {
11624            this.buffer.update(cx, |buffer, cx| {
11625                buffer.edit(edits, None, cx);
11626            });
11627
11628            this.change_selections(Default::default(), window, cx, |s| {
11629                s.select(new_selections);
11630            });
11631
11632            this.request_autoscroll(Autoscroll::fit(), cx);
11633        });
11634    }
11635
11636    pub fn move_selection_on_drop(
11637        &mut self,
11638        selection: &Selection<Anchor>,
11639        target: DisplayPoint,
11640        is_cut: bool,
11641        window: &mut Window,
11642        cx: &mut Context<Self>,
11643    ) {
11644        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11645        let buffer = display_map.buffer_snapshot();
11646        let mut edits = Vec::new();
11647        let insert_point = display_map
11648            .clip_point(target, Bias::Left)
11649            .to_point(&display_map);
11650        let text = buffer
11651            .text_for_range(selection.start..selection.end)
11652            .collect::<String>();
11653        if is_cut {
11654            edits.push(((selection.start..selection.end), String::new()));
11655        }
11656        let insert_anchor = buffer.anchor_before(insert_point);
11657        edits.push(((insert_anchor..insert_anchor), text));
11658        let last_edit_start = insert_anchor.bias_left(buffer);
11659        let last_edit_end = insert_anchor.bias_right(buffer);
11660        self.transact(window, cx, |this, window, cx| {
11661            this.buffer.update(cx, |buffer, cx| {
11662                buffer.edit(edits, None, cx);
11663            });
11664            this.change_selections(Default::default(), window, cx, |s| {
11665                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11666            });
11667        });
11668    }
11669
11670    pub fn clear_selection_drag_state(&mut self) {
11671        self.selection_drag_state = SelectionDragState::None;
11672    }
11673
11674    pub fn duplicate(
11675        &mut self,
11676        upwards: bool,
11677        whole_lines: bool,
11678        window: &mut Window,
11679        cx: &mut Context<Self>,
11680    ) {
11681        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11682
11683        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11684        let buffer = display_map.buffer_snapshot();
11685        let selections = self.selections.all::<Point>(cx);
11686
11687        let mut edits = Vec::new();
11688        let mut selections_iter = selections.iter().peekable();
11689        while let Some(selection) = selections_iter.next() {
11690            let mut rows = selection.spanned_rows(false, &display_map);
11691            // duplicate line-wise
11692            if whole_lines || selection.start == selection.end {
11693                // Avoid duplicating the same lines twice.
11694                while let Some(next_selection) = selections_iter.peek() {
11695                    let next_rows = next_selection.spanned_rows(false, &display_map);
11696                    if next_rows.start < rows.end {
11697                        rows.end = next_rows.end;
11698                        selections_iter.next().unwrap();
11699                    } else {
11700                        break;
11701                    }
11702                }
11703
11704                // Copy the text from the selected row region and splice it either at the start
11705                // or end of the region.
11706                let start = Point::new(rows.start.0, 0);
11707                let end = Point::new(
11708                    rows.end.previous_row().0,
11709                    buffer.line_len(rows.end.previous_row()),
11710                );
11711
11712                let mut text = buffer.text_for_range(start..end).collect::<String>();
11713
11714                let insert_location = if upwards {
11715                    // When duplicating upward, we need to insert before the current line.
11716                    // If we're on the last line and it doesn't end with a newline,
11717                    // we need to add a newline before the duplicated content.
11718                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11719                        && buffer.max_point().column > 0
11720                        && !text.ends_with('\n');
11721
11722                    if needs_leading_newline {
11723                        text.insert(0, '\n');
11724                        end
11725                    } else {
11726                        text.push('\n');
11727                        Point::new(rows.end.0, 0)
11728                    }
11729                } else {
11730                    text.push('\n');
11731                    start
11732                };
11733                edits.push((insert_location..insert_location, text));
11734            } else {
11735                // duplicate character-wise
11736                let start = selection.start;
11737                let end = selection.end;
11738                let text = buffer.text_for_range(start..end).collect::<String>();
11739                edits.push((selection.end..selection.end, text));
11740            }
11741        }
11742
11743        self.transact(window, cx, |this, _, cx| {
11744            this.buffer.update(cx, |buffer, cx| {
11745                buffer.edit(edits, None, cx);
11746            });
11747
11748            this.request_autoscroll(Autoscroll::fit(), cx);
11749        });
11750    }
11751
11752    pub fn duplicate_line_up(
11753        &mut self,
11754        _: &DuplicateLineUp,
11755        window: &mut Window,
11756        cx: &mut Context<Self>,
11757    ) {
11758        self.duplicate(true, true, window, cx);
11759    }
11760
11761    pub fn duplicate_line_down(
11762        &mut self,
11763        _: &DuplicateLineDown,
11764        window: &mut Window,
11765        cx: &mut Context<Self>,
11766    ) {
11767        self.duplicate(false, true, window, cx);
11768    }
11769
11770    pub fn duplicate_selection(
11771        &mut self,
11772        _: &DuplicateSelection,
11773        window: &mut Window,
11774        cx: &mut Context<Self>,
11775    ) {
11776        self.duplicate(false, false, window, cx);
11777    }
11778
11779    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11781        if self.mode.is_single_line() {
11782            cx.propagate();
11783            return;
11784        }
11785
11786        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11787        let buffer = self.buffer.read(cx).snapshot(cx);
11788
11789        let mut edits = Vec::new();
11790        let mut unfold_ranges = Vec::new();
11791        let mut refold_creases = Vec::new();
11792
11793        let selections = self.selections.all::<Point>(cx);
11794        let mut selections = selections.iter().peekable();
11795        let mut contiguous_row_selections = Vec::new();
11796        let mut new_selections = Vec::new();
11797
11798        while let Some(selection) = selections.next() {
11799            // Find all the selections that span a contiguous row range
11800            let (start_row, end_row) = consume_contiguous_rows(
11801                &mut contiguous_row_selections,
11802                selection,
11803                &display_map,
11804                &mut selections,
11805            );
11806
11807            // Move the text spanned by the row range to be before the line preceding the row range
11808            if start_row.0 > 0 {
11809                let range_to_move = Point::new(
11810                    start_row.previous_row().0,
11811                    buffer.line_len(start_row.previous_row()),
11812                )
11813                    ..Point::new(
11814                        end_row.previous_row().0,
11815                        buffer.line_len(end_row.previous_row()),
11816                    );
11817                let insertion_point = display_map
11818                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11819                    .0;
11820
11821                // Don't move lines across excerpts
11822                if buffer
11823                    .excerpt_containing(insertion_point..range_to_move.end)
11824                    .is_some()
11825                {
11826                    let text = buffer
11827                        .text_for_range(range_to_move.clone())
11828                        .flat_map(|s| s.chars())
11829                        .skip(1)
11830                        .chain(['\n'])
11831                        .collect::<String>();
11832
11833                    edits.push((
11834                        buffer.anchor_after(range_to_move.start)
11835                            ..buffer.anchor_before(range_to_move.end),
11836                        String::new(),
11837                    ));
11838                    let insertion_anchor = buffer.anchor_after(insertion_point);
11839                    edits.push((insertion_anchor..insertion_anchor, text));
11840
11841                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11842
11843                    // Move selections up
11844                    new_selections.extend(contiguous_row_selections.drain(..).map(
11845                        |mut selection| {
11846                            selection.start.row -= row_delta;
11847                            selection.end.row -= row_delta;
11848                            selection
11849                        },
11850                    ));
11851
11852                    // Move folds up
11853                    unfold_ranges.push(range_to_move.clone());
11854                    for fold in display_map.folds_in_range(
11855                        buffer.anchor_before(range_to_move.start)
11856                            ..buffer.anchor_after(range_to_move.end),
11857                    ) {
11858                        let mut start = fold.range.start.to_point(&buffer);
11859                        let mut end = fold.range.end.to_point(&buffer);
11860                        start.row -= row_delta;
11861                        end.row -= row_delta;
11862                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11863                    }
11864                }
11865            }
11866
11867            // If we didn't move line(s), preserve the existing selections
11868            new_selections.append(&mut contiguous_row_selections);
11869        }
11870
11871        self.transact(window, cx, |this, window, cx| {
11872            this.unfold_ranges(&unfold_ranges, true, true, cx);
11873            this.buffer.update(cx, |buffer, cx| {
11874                for (range, text) in edits {
11875                    buffer.edit([(range, text)], None, cx);
11876                }
11877            });
11878            this.fold_creases(refold_creases, true, window, cx);
11879            this.change_selections(Default::default(), window, cx, |s| {
11880                s.select(new_selections);
11881            })
11882        });
11883    }
11884
11885    pub fn move_line_down(
11886        &mut self,
11887        _: &MoveLineDown,
11888        window: &mut Window,
11889        cx: &mut Context<Self>,
11890    ) {
11891        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11892        if self.mode.is_single_line() {
11893            cx.propagate();
11894            return;
11895        }
11896
11897        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11898        let buffer = self.buffer.read(cx).snapshot(cx);
11899
11900        let mut edits = Vec::new();
11901        let mut unfold_ranges = Vec::new();
11902        let mut refold_creases = Vec::new();
11903
11904        let selections = self.selections.all::<Point>(cx);
11905        let mut selections = selections.iter().peekable();
11906        let mut contiguous_row_selections = Vec::new();
11907        let mut new_selections = Vec::new();
11908
11909        while let Some(selection) = selections.next() {
11910            // Find all the selections that span a contiguous row range
11911            let (start_row, end_row) = consume_contiguous_rows(
11912                &mut contiguous_row_selections,
11913                selection,
11914                &display_map,
11915                &mut selections,
11916            );
11917
11918            // Move the text spanned by the row range to be after the last line of the row range
11919            if end_row.0 <= buffer.max_point().row {
11920                let range_to_move =
11921                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11922                let insertion_point = display_map
11923                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11924                    .0;
11925
11926                // Don't move lines across excerpt boundaries
11927                if buffer
11928                    .excerpt_containing(range_to_move.start..insertion_point)
11929                    .is_some()
11930                {
11931                    let mut text = String::from("\n");
11932                    text.extend(buffer.text_for_range(range_to_move.clone()));
11933                    text.pop(); // Drop trailing newline
11934                    edits.push((
11935                        buffer.anchor_after(range_to_move.start)
11936                            ..buffer.anchor_before(range_to_move.end),
11937                        String::new(),
11938                    ));
11939                    let insertion_anchor = buffer.anchor_after(insertion_point);
11940                    edits.push((insertion_anchor..insertion_anchor, text));
11941
11942                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11943
11944                    // Move selections down
11945                    new_selections.extend(contiguous_row_selections.drain(..).map(
11946                        |mut selection| {
11947                            selection.start.row += row_delta;
11948                            selection.end.row += row_delta;
11949                            selection
11950                        },
11951                    ));
11952
11953                    // Move folds down
11954                    unfold_ranges.push(range_to_move.clone());
11955                    for fold in display_map.folds_in_range(
11956                        buffer.anchor_before(range_to_move.start)
11957                            ..buffer.anchor_after(range_to_move.end),
11958                    ) {
11959                        let mut start = fold.range.start.to_point(&buffer);
11960                        let mut end = fold.range.end.to_point(&buffer);
11961                        start.row += row_delta;
11962                        end.row += row_delta;
11963                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11964                    }
11965                }
11966            }
11967
11968            // If we didn't move line(s), preserve the existing selections
11969            new_selections.append(&mut contiguous_row_selections);
11970        }
11971
11972        self.transact(window, cx, |this, window, cx| {
11973            this.unfold_ranges(&unfold_ranges, true, true, cx);
11974            this.buffer.update(cx, |buffer, cx| {
11975                for (range, text) in edits {
11976                    buffer.edit([(range, text)], None, cx);
11977                }
11978            });
11979            this.fold_creases(refold_creases, true, window, cx);
11980            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11981        });
11982    }
11983
11984    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11985        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11986        let text_layout_details = &self.text_layout_details(window);
11987        self.transact(window, cx, |this, window, cx| {
11988            let edits = this.change_selections(Default::default(), window, cx, |s| {
11989                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11990                s.move_with(|display_map, selection| {
11991                    if !selection.is_empty() {
11992                        return;
11993                    }
11994
11995                    let mut head = selection.head();
11996                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11997                    if head.column() == display_map.line_len(head.row()) {
11998                        transpose_offset = display_map
11999                            .buffer_snapshot()
12000                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12001                    }
12002
12003                    if transpose_offset == 0 {
12004                        return;
12005                    }
12006
12007                    *head.column_mut() += 1;
12008                    head = display_map.clip_point(head, Bias::Right);
12009                    let goal = SelectionGoal::HorizontalPosition(
12010                        display_map
12011                            .x_for_display_point(head, text_layout_details)
12012                            .into(),
12013                    );
12014                    selection.collapse_to(head, goal);
12015
12016                    let transpose_start = display_map
12017                        .buffer_snapshot()
12018                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12019                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12020                        let transpose_end = display_map
12021                            .buffer_snapshot()
12022                            .clip_offset(transpose_offset + 1, Bias::Right);
12023                        if let Some(ch) = display_map
12024                            .buffer_snapshot()
12025                            .chars_at(transpose_start)
12026                            .next()
12027                        {
12028                            edits.push((transpose_start..transpose_offset, String::new()));
12029                            edits.push((transpose_end..transpose_end, ch.to_string()));
12030                        }
12031                    }
12032                });
12033                edits
12034            });
12035            this.buffer
12036                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12037            let selections = this.selections.all::<usize>(cx);
12038            this.change_selections(Default::default(), window, cx, |s| {
12039                s.select(selections);
12040            });
12041        });
12042    }
12043
12044    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12045        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12046        if self.mode.is_single_line() {
12047            cx.propagate();
12048            return;
12049        }
12050
12051        self.rewrap_impl(RewrapOptions::default(), cx)
12052    }
12053
12054    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12055        let buffer = self.buffer.read(cx).snapshot(cx);
12056        let selections = self.selections.all::<Point>(cx);
12057
12058        #[derive(Clone, Debug, PartialEq)]
12059        enum CommentFormat {
12060            /// single line comment, with prefix for line
12061            Line(String),
12062            /// single line within a block comment, with prefix for line
12063            BlockLine(String),
12064            /// a single line of a block comment that includes the initial delimiter
12065            BlockCommentWithStart(BlockCommentConfig),
12066            /// a single line of a block comment that includes the ending delimiter
12067            BlockCommentWithEnd(BlockCommentConfig),
12068        }
12069
12070        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12071        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12072            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12073                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12074                .peekable();
12075
12076            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12077                row
12078            } else {
12079                return Vec::new();
12080            };
12081
12082            let language_settings = buffer.language_settings_at(selection.head(), cx);
12083            let language_scope = buffer.language_scope_at(selection.head());
12084
12085            let indent_and_prefix_for_row =
12086                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12087                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12088                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12089                        &language_scope
12090                    {
12091                        let indent_end = Point::new(row, indent.len);
12092                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12093                        let line_text_after_indent = buffer
12094                            .text_for_range(indent_end..line_end)
12095                            .collect::<String>();
12096
12097                        let is_within_comment_override = buffer
12098                            .language_scope_at(indent_end)
12099                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12100                        let comment_delimiters = if is_within_comment_override {
12101                            // we are within a comment syntax node, but we don't
12102                            // yet know what kind of comment: block, doc or line
12103                            match (
12104                                language_scope.documentation_comment(),
12105                                language_scope.block_comment(),
12106                            ) {
12107                                (Some(config), _) | (_, Some(config))
12108                                    if buffer.contains_str_at(indent_end, &config.start) =>
12109                                {
12110                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12111                                }
12112                                (Some(config), _) | (_, Some(config))
12113                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12114                                {
12115                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12116                                }
12117                                (Some(config), _) | (_, Some(config))
12118                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12119                                {
12120                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12121                                }
12122                                (_, _) => language_scope
12123                                    .line_comment_prefixes()
12124                                    .iter()
12125                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12126                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12127                            }
12128                        } else {
12129                            // we not in an overridden comment node, but we may
12130                            // be within a non-overridden line comment node
12131                            language_scope
12132                                .line_comment_prefixes()
12133                                .iter()
12134                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12135                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12136                        };
12137
12138                        let rewrap_prefix = language_scope
12139                            .rewrap_prefixes()
12140                            .iter()
12141                            .find_map(|prefix_regex| {
12142                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12143                                    if mat.start() == 0 {
12144                                        Some(mat.as_str().to_string())
12145                                    } else {
12146                                        None
12147                                    }
12148                                })
12149                            })
12150                            .flatten();
12151                        (comment_delimiters, rewrap_prefix)
12152                    } else {
12153                        (None, None)
12154                    };
12155                    (indent, comment_prefix, rewrap_prefix)
12156                };
12157
12158            let mut ranges = Vec::new();
12159            let from_empty_selection = selection.is_empty();
12160
12161            let mut current_range_start = first_row;
12162            let mut prev_row = first_row;
12163            let (
12164                mut current_range_indent,
12165                mut current_range_comment_delimiters,
12166                mut current_range_rewrap_prefix,
12167            ) = indent_and_prefix_for_row(first_row);
12168
12169            for row in non_blank_rows_iter.skip(1) {
12170                let has_paragraph_break = row > prev_row + 1;
12171
12172                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12173                    indent_and_prefix_for_row(row);
12174
12175                let has_indent_change = row_indent != current_range_indent;
12176                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12177
12178                let has_boundary_change = has_comment_change
12179                    || row_rewrap_prefix.is_some()
12180                    || (has_indent_change && current_range_comment_delimiters.is_some());
12181
12182                if has_paragraph_break || has_boundary_change {
12183                    ranges.push((
12184                        language_settings.clone(),
12185                        Point::new(current_range_start, 0)
12186                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12187                        current_range_indent,
12188                        current_range_comment_delimiters.clone(),
12189                        current_range_rewrap_prefix.clone(),
12190                        from_empty_selection,
12191                    ));
12192                    current_range_start = row;
12193                    current_range_indent = row_indent;
12194                    current_range_comment_delimiters = row_comment_delimiters;
12195                    current_range_rewrap_prefix = row_rewrap_prefix;
12196                }
12197                prev_row = row;
12198            }
12199
12200            ranges.push((
12201                language_settings.clone(),
12202                Point::new(current_range_start, 0)
12203                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12204                current_range_indent,
12205                current_range_comment_delimiters,
12206                current_range_rewrap_prefix,
12207                from_empty_selection,
12208            ));
12209
12210            ranges
12211        });
12212
12213        let mut edits = Vec::new();
12214        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12215
12216        for (
12217            language_settings,
12218            wrap_range,
12219            mut indent_size,
12220            comment_prefix,
12221            rewrap_prefix,
12222            from_empty_selection,
12223        ) in wrap_ranges
12224        {
12225            let mut start_row = wrap_range.start.row;
12226            let mut end_row = wrap_range.end.row;
12227
12228            // Skip selections that overlap with a range that has already been rewrapped.
12229            let selection_range = start_row..end_row;
12230            if rewrapped_row_ranges
12231                .iter()
12232                .any(|range| range.overlaps(&selection_range))
12233            {
12234                continue;
12235            }
12236
12237            let tab_size = language_settings.tab_size;
12238
12239            let (line_prefix, inside_comment) = match &comment_prefix {
12240                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12241                    (Some(prefix.as_str()), true)
12242                }
12243                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12244                    (Some(prefix.as_ref()), true)
12245                }
12246                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12247                    start: _,
12248                    end: _,
12249                    prefix,
12250                    tab_size,
12251                })) => {
12252                    indent_size.len += tab_size;
12253                    (Some(prefix.as_ref()), true)
12254                }
12255                None => (None, false),
12256            };
12257            let indent_prefix = indent_size.chars().collect::<String>();
12258            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12259
12260            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12261                RewrapBehavior::InComments => inside_comment,
12262                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12263                RewrapBehavior::Anywhere => true,
12264            };
12265
12266            let should_rewrap = options.override_language_settings
12267                || allow_rewrap_based_on_language
12268                || self.hard_wrap.is_some();
12269            if !should_rewrap {
12270                continue;
12271            }
12272
12273            if from_empty_selection {
12274                'expand_upwards: while start_row > 0 {
12275                    let prev_row = start_row - 1;
12276                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12277                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12278                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12279                    {
12280                        start_row = prev_row;
12281                    } else {
12282                        break 'expand_upwards;
12283                    }
12284                }
12285
12286                'expand_downwards: while end_row < buffer.max_point().row {
12287                    let next_row = end_row + 1;
12288                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12289                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12290                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12291                    {
12292                        end_row = next_row;
12293                    } else {
12294                        break 'expand_downwards;
12295                    }
12296                }
12297            }
12298
12299            let start = Point::new(start_row, 0);
12300            let start_offset = ToOffset::to_offset(&start, &buffer);
12301            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12302            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12303            let mut first_line_delimiter = None;
12304            let mut last_line_delimiter = None;
12305            let Some(lines_without_prefixes) = selection_text
12306                .lines()
12307                .enumerate()
12308                .map(|(ix, line)| {
12309                    let line_trimmed = line.trim_start();
12310                    if rewrap_prefix.is_some() && ix > 0 {
12311                        Ok(line_trimmed)
12312                    } else if let Some(
12313                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12314                            start,
12315                            prefix,
12316                            end,
12317                            tab_size,
12318                        })
12319                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12320                            start,
12321                            prefix,
12322                            end,
12323                            tab_size,
12324                        }),
12325                    ) = &comment_prefix
12326                    {
12327                        let line_trimmed = line_trimmed
12328                            .strip_prefix(start.as_ref())
12329                            .map(|s| {
12330                                let mut indent_size = indent_size;
12331                                indent_size.len -= tab_size;
12332                                let indent_prefix: String = indent_size.chars().collect();
12333                                first_line_delimiter = Some((indent_prefix, start));
12334                                s.trim_start()
12335                            })
12336                            .unwrap_or(line_trimmed);
12337                        let line_trimmed = line_trimmed
12338                            .strip_suffix(end.as_ref())
12339                            .map(|s| {
12340                                last_line_delimiter = Some(end);
12341                                s.trim_end()
12342                            })
12343                            .unwrap_or(line_trimmed);
12344                        let line_trimmed = line_trimmed
12345                            .strip_prefix(prefix.as_ref())
12346                            .unwrap_or(line_trimmed);
12347                        Ok(line_trimmed)
12348                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12349                        line_trimmed.strip_prefix(prefix).with_context(|| {
12350                            format!("line did not start with prefix {prefix:?}: {line:?}")
12351                        })
12352                    } else {
12353                        line_trimmed
12354                            .strip_prefix(&line_prefix.trim_start())
12355                            .with_context(|| {
12356                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12357                            })
12358                    }
12359                })
12360                .collect::<Result<Vec<_>, _>>()
12361                .log_err()
12362            else {
12363                continue;
12364            };
12365
12366            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12367                buffer
12368                    .language_settings_at(Point::new(start_row, 0), cx)
12369                    .preferred_line_length as usize
12370            });
12371
12372            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12373                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12374            } else {
12375                line_prefix.clone()
12376            };
12377
12378            let wrapped_text = {
12379                let mut wrapped_text = wrap_with_prefix(
12380                    line_prefix,
12381                    subsequent_lines_prefix,
12382                    lines_without_prefixes.join("\n"),
12383                    wrap_column,
12384                    tab_size,
12385                    options.preserve_existing_whitespace,
12386                );
12387
12388                if let Some((indent, delimiter)) = first_line_delimiter {
12389                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12390                }
12391                if let Some(last_line) = last_line_delimiter {
12392                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12393                }
12394
12395                wrapped_text
12396            };
12397
12398            // TODO: should always use char-based diff while still supporting cursor behavior that
12399            // matches vim.
12400            let mut diff_options = DiffOptions::default();
12401            if options.override_language_settings {
12402                diff_options.max_word_diff_len = 0;
12403                diff_options.max_word_diff_line_count = 0;
12404            } else {
12405                diff_options.max_word_diff_len = usize::MAX;
12406                diff_options.max_word_diff_line_count = usize::MAX;
12407            }
12408
12409            for (old_range, new_text) in
12410                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12411            {
12412                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12413                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12414                edits.push((edit_start..edit_end, new_text));
12415            }
12416
12417            rewrapped_row_ranges.push(start_row..=end_row);
12418        }
12419
12420        self.buffer
12421            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12422    }
12423
12424    pub fn cut_common(
12425        &mut self,
12426        cut_no_selection_line: bool,
12427        window: &mut Window,
12428        cx: &mut Context<Self>,
12429    ) -> ClipboardItem {
12430        let mut text = String::new();
12431        let buffer = self.buffer.read(cx).snapshot(cx);
12432        let mut selections = self.selections.all::<Point>(cx);
12433        let mut clipboard_selections = Vec::with_capacity(selections.len());
12434        {
12435            let max_point = buffer.max_point();
12436            let mut is_first = true;
12437            for selection in &mut selections {
12438                let is_entire_line =
12439                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12440                if is_entire_line {
12441                    selection.start = Point::new(selection.start.row, 0);
12442                    if !selection.is_empty() && selection.end.column == 0 {
12443                        selection.end = cmp::min(max_point, selection.end);
12444                    } else {
12445                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12446                    }
12447                    selection.goal = SelectionGoal::None;
12448                }
12449                if is_first {
12450                    is_first = false;
12451                } else {
12452                    text += "\n";
12453                }
12454                let mut len = 0;
12455                for chunk in buffer.text_for_range(selection.start..selection.end) {
12456                    text.push_str(chunk);
12457                    len += chunk.len();
12458                }
12459                clipboard_selections.push(ClipboardSelection {
12460                    len,
12461                    is_entire_line,
12462                    first_line_indent: buffer
12463                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12464                        .len,
12465                });
12466            }
12467        }
12468
12469        self.transact(window, cx, |this, window, cx| {
12470            this.change_selections(Default::default(), window, cx, |s| {
12471                s.select(selections);
12472            });
12473            this.insert("", window, cx);
12474        });
12475        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12476    }
12477
12478    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12480        let item = self.cut_common(true, window, cx);
12481        cx.write_to_clipboard(item);
12482    }
12483
12484    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12486        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12487            s.move_with(|snapshot, sel| {
12488                if sel.is_empty() {
12489                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12490                }
12491                if sel.is_empty() {
12492                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12493                }
12494            });
12495        });
12496        let item = self.cut_common(false, window, cx);
12497        cx.set_global(KillRing(item))
12498    }
12499
12500    pub fn kill_ring_yank(
12501        &mut self,
12502        _: &KillRingYank,
12503        window: &mut Window,
12504        cx: &mut Context<Self>,
12505    ) {
12506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12507        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12508            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12509                (kill_ring.text().to_string(), kill_ring.metadata_json())
12510            } else {
12511                return;
12512            }
12513        } else {
12514            return;
12515        };
12516        self.do_paste(&text, metadata, false, window, cx);
12517    }
12518
12519    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12520        self.do_copy(true, cx);
12521    }
12522
12523    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12524        self.do_copy(false, cx);
12525    }
12526
12527    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12528        let selections = self.selections.all::<Point>(cx);
12529        let buffer = self.buffer.read(cx).read(cx);
12530        let mut text = String::new();
12531
12532        let mut clipboard_selections = Vec::with_capacity(selections.len());
12533        {
12534            let max_point = buffer.max_point();
12535            let mut is_first = true;
12536            for selection in &selections {
12537                let mut start = selection.start;
12538                let mut end = selection.end;
12539                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12540                let mut add_trailing_newline = false;
12541                if is_entire_line {
12542                    start = Point::new(start.row, 0);
12543                    let next_line_start = Point::new(end.row + 1, 0);
12544                    if next_line_start <= max_point {
12545                        end = next_line_start;
12546                    } else {
12547                        // We're on the last line without a trailing newline.
12548                        // Copy to the end of the line and add a newline afterwards.
12549                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12550                        add_trailing_newline = true;
12551                    }
12552                }
12553
12554                let mut trimmed_selections = Vec::new();
12555                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12556                    let row = MultiBufferRow(start.row);
12557                    let first_indent = buffer.indent_size_for_line(row);
12558                    if first_indent.len == 0 || start.column > first_indent.len {
12559                        trimmed_selections.push(start..end);
12560                    } else {
12561                        trimmed_selections.push(
12562                            Point::new(row.0, first_indent.len)
12563                                ..Point::new(row.0, buffer.line_len(row)),
12564                        );
12565                        for row in start.row + 1..=end.row {
12566                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12567                            if row == end.row {
12568                                line_len = end.column;
12569                            }
12570                            if line_len == 0 {
12571                                trimmed_selections
12572                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12573                                continue;
12574                            }
12575                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12576                            if row_indent_size.len >= first_indent.len {
12577                                trimmed_selections.push(
12578                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12579                                );
12580                            } else {
12581                                trimmed_selections.clear();
12582                                trimmed_selections.push(start..end);
12583                                break;
12584                            }
12585                        }
12586                    }
12587                } else {
12588                    trimmed_selections.push(start..end);
12589                }
12590
12591                for trimmed_range in trimmed_selections {
12592                    if is_first {
12593                        is_first = false;
12594                    } else {
12595                        text += "\n";
12596                    }
12597                    let mut len = 0;
12598                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12599                        text.push_str(chunk);
12600                        len += chunk.len();
12601                    }
12602                    if add_trailing_newline {
12603                        text.push('\n');
12604                        len += 1;
12605                    }
12606                    clipboard_selections.push(ClipboardSelection {
12607                        len,
12608                        is_entire_line,
12609                        first_line_indent: buffer
12610                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12611                            .len,
12612                    });
12613                }
12614            }
12615        }
12616
12617        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12618            text,
12619            clipboard_selections,
12620        ));
12621    }
12622
12623    pub fn do_paste(
12624        &mut self,
12625        text: &String,
12626        clipboard_selections: Option<Vec<ClipboardSelection>>,
12627        handle_entire_lines: bool,
12628        window: &mut Window,
12629        cx: &mut Context<Self>,
12630    ) {
12631        if self.read_only(cx) {
12632            return;
12633        }
12634
12635        let clipboard_text = Cow::Borrowed(text.as_str());
12636
12637        self.transact(window, cx, |this, window, cx| {
12638            let had_active_edit_prediction = this.has_active_edit_prediction();
12639            let old_selections = this.selections.all::<usize>(cx);
12640            let cursor_offset = this.selections.last::<usize>(cx).head();
12641
12642            if let Some(mut clipboard_selections) = clipboard_selections {
12643                let all_selections_were_entire_line =
12644                    clipboard_selections.iter().all(|s| s.is_entire_line);
12645                let first_selection_indent_column =
12646                    clipboard_selections.first().map(|s| s.first_line_indent);
12647                if clipboard_selections.len() != old_selections.len() {
12648                    clipboard_selections.drain(..);
12649                }
12650                let mut auto_indent_on_paste = true;
12651
12652                this.buffer.update(cx, |buffer, cx| {
12653                    let snapshot = buffer.read(cx);
12654                    auto_indent_on_paste = snapshot
12655                        .language_settings_at(cursor_offset, cx)
12656                        .auto_indent_on_paste;
12657
12658                    let mut start_offset = 0;
12659                    let mut edits = Vec::new();
12660                    let mut original_indent_columns = Vec::new();
12661                    for (ix, selection) in old_selections.iter().enumerate() {
12662                        let to_insert;
12663                        let entire_line;
12664                        let original_indent_column;
12665                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12666                            let end_offset = start_offset + clipboard_selection.len;
12667                            to_insert = &clipboard_text[start_offset..end_offset];
12668                            entire_line = clipboard_selection.is_entire_line;
12669                            start_offset = end_offset + 1;
12670                            original_indent_column = Some(clipboard_selection.first_line_indent);
12671                        } else {
12672                            to_insert = &*clipboard_text;
12673                            entire_line = all_selections_were_entire_line;
12674                            original_indent_column = first_selection_indent_column
12675                        }
12676
12677                        let (range, to_insert) =
12678                            if selection.is_empty() && handle_entire_lines && entire_line {
12679                                // If the corresponding selection was empty when this slice of the
12680                                // clipboard text was written, then the entire line containing the
12681                                // selection was copied. If this selection is also currently empty,
12682                                // then paste the line before the current line of the buffer.
12683                                let column = selection.start.to_point(&snapshot).column as usize;
12684                                let line_start = selection.start - column;
12685                                (line_start..line_start, Cow::Borrowed(to_insert))
12686                            } else {
12687                                let language = snapshot.language_at(selection.head());
12688                                let range = selection.range();
12689                                if let Some(language) = language
12690                                    && language.name() == "Markdown".into()
12691                                {
12692                                    edit_for_markdown_paste(
12693                                        &snapshot,
12694                                        range,
12695                                        to_insert,
12696                                        url::Url::parse(to_insert).ok(),
12697                                    )
12698                                } else {
12699                                    (range, Cow::Borrowed(to_insert))
12700                                }
12701                            };
12702
12703                        edits.push((range, to_insert));
12704                        original_indent_columns.push(original_indent_column);
12705                    }
12706                    drop(snapshot);
12707
12708                    buffer.edit(
12709                        edits,
12710                        if auto_indent_on_paste {
12711                            Some(AutoindentMode::Block {
12712                                original_indent_columns,
12713                            })
12714                        } else {
12715                            None
12716                        },
12717                        cx,
12718                    );
12719                });
12720
12721                let selections = this.selections.all::<usize>(cx);
12722                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12723            } else {
12724                let url = url::Url::parse(&clipboard_text).ok();
12725
12726                let auto_indent_mode = if !clipboard_text.is_empty() {
12727                    Some(AutoindentMode::Block {
12728                        original_indent_columns: Vec::new(),
12729                    })
12730                } else {
12731                    None
12732                };
12733
12734                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12735                    let snapshot = buffer.snapshot(cx);
12736
12737                    let anchors = old_selections
12738                        .iter()
12739                        .map(|s| {
12740                            let anchor = snapshot.anchor_after(s.head());
12741                            s.map(|_| anchor)
12742                        })
12743                        .collect::<Vec<_>>();
12744
12745                    let mut edits = Vec::new();
12746
12747                    for selection in old_selections.iter() {
12748                        let language = snapshot.language_at(selection.head());
12749                        let range = selection.range();
12750
12751                        let (edit_range, edit_text) = if let Some(language) = language
12752                            && language.name() == "Markdown".into()
12753                        {
12754                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12755                        } else {
12756                            (range, clipboard_text.clone())
12757                        };
12758
12759                        edits.push((edit_range, edit_text));
12760                    }
12761
12762                    drop(snapshot);
12763                    buffer.edit(edits, auto_indent_mode, cx);
12764
12765                    anchors
12766                });
12767
12768                this.change_selections(Default::default(), window, cx, |s| {
12769                    s.select_anchors(selection_anchors);
12770                });
12771            }
12772
12773            let trigger_in_words =
12774                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12775
12776            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12777        });
12778    }
12779
12780    pub fn diff_clipboard_with_selection(
12781        &mut self,
12782        _: &DiffClipboardWithSelection,
12783        window: &mut Window,
12784        cx: &mut Context<Self>,
12785    ) {
12786        let selections = self.selections.all::<usize>(cx);
12787
12788        if selections.is_empty() {
12789            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12790            return;
12791        };
12792
12793        let clipboard_text = match cx.read_from_clipboard() {
12794            Some(item) => match item.entries().first() {
12795                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12796                _ => None,
12797            },
12798            None => None,
12799        };
12800
12801        let Some(clipboard_text) = clipboard_text else {
12802            log::warn!("Clipboard doesn't contain text.");
12803            return;
12804        };
12805
12806        window.dispatch_action(
12807            Box::new(DiffClipboardWithSelectionData {
12808                clipboard_text,
12809                editor: cx.entity(),
12810            }),
12811            cx,
12812        );
12813    }
12814
12815    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12817        if let Some(item) = cx.read_from_clipboard() {
12818            let entries = item.entries();
12819
12820            match entries.first() {
12821                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12822                // of all the pasted entries.
12823                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12824                    .do_paste(
12825                        clipboard_string.text(),
12826                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12827                        true,
12828                        window,
12829                        cx,
12830                    ),
12831                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12832            }
12833        }
12834    }
12835
12836    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12837        if self.read_only(cx) {
12838            return;
12839        }
12840
12841        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12842
12843        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12844            if let Some((selections, _)) =
12845                self.selection_history.transaction(transaction_id).cloned()
12846            {
12847                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12848                    s.select_anchors(selections.to_vec());
12849                });
12850            } else {
12851                log::error!(
12852                    "No entry in selection_history found for undo. \
12853                     This may correspond to a bug where undo does not update the selection. \
12854                     If this is occurring, please add details to \
12855                     https://github.com/zed-industries/zed/issues/22692"
12856                );
12857            }
12858            self.request_autoscroll(Autoscroll::fit(), cx);
12859            self.unmark_text(window, cx);
12860            self.refresh_edit_prediction(true, false, window, cx);
12861            cx.emit(EditorEvent::Edited { transaction_id });
12862            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12863        }
12864    }
12865
12866    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12867        if self.read_only(cx) {
12868            return;
12869        }
12870
12871        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12872
12873        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12874            if let Some((_, Some(selections))) =
12875                self.selection_history.transaction(transaction_id).cloned()
12876            {
12877                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12878                    s.select_anchors(selections.to_vec());
12879                });
12880            } else {
12881                log::error!(
12882                    "No entry in selection_history found for redo. \
12883                     This may correspond to a bug where undo does not update the selection. \
12884                     If this is occurring, please add details to \
12885                     https://github.com/zed-industries/zed/issues/22692"
12886                );
12887            }
12888            self.request_autoscroll(Autoscroll::fit(), cx);
12889            self.unmark_text(window, cx);
12890            self.refresh_edit_prediction(true, false, window, cx);
12891            cx.emit(EditorEvent::Edited { transaction_id });
12892        }
12893    }
12894
12895    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12896        self.buffer
12897            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12898    }
12899
12900    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12901        self.buffer
12902            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12903    }
12904
12905    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12907        self.change_selections(Default::default(), window, cx, |s| {
12908            s.move_with(|map, selection| {
12909                let cursor = if selection.is_empty() {
12910                    movement::left(map, selection.start)
12911                } else {
12912                    selection.start
12913                };
12914                selection.collapse_to(cursor, SelectionGoal::None);
12915            });
12916        })
12917    }
12918
12919    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12921        self.change_selections(Default::default(), window, cx, |s| {
12922            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12923        })
12924    }
12925
12926    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12928        self.change_selections(Default::default(), window, cx, |s| {
12929            s.move_with(|map, selection| {
12930                let cursor = if selection.is_empty() {
12931                    movement::right(map, selection.end)
12932                } else {
12933                    selection.end
12934                };
12935                selection.collapse_to(cursor, SelectionGoal::None)
12936            });
12937        })
12938    }
12939
12940    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12941        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12942        self.change_selections(Default::default(), window, cx, |s| {
12943            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12944        });
12945    }
12946
12947    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12948        if self.take_rename(true, window, cx).is_some() {
12949            return;
12950        }
12951
12952        if self.mode.is_single_line() {
12953            cx.propagate();
12954            return;
12955        }
12956
12957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12958
12959        let text_layout_details = &self.text_layout_details(window);
12960        let selection_count = self.selections.count();
12961        let first_selection = self.selections.first_anchor();
12962
12963        self.change_selections(Default::default(), window, cx, |s| {
12964            s.move_with(|map, selection| {
12965                if !selection.is_empty() {
12966                    selection.goal = SelectionGoal::None;
12967                }
12968                let (cursor, goal) = movement::up(
12969                    map,
12970                    selection.start,
12971                    selection.goal,
12972                    false,
12973                    text_layout_details,
12974                );
12975                selection.collapse_to(cursor, goal);
12976            });
12977        });
12978
12979        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12980        {
12981            cx.propagate();
12982        }
12983    }
12984
12985    pub fn move_up_by_lines(
12986        &mut self,
12987        action: &MoveUpByLines,
12988        window: &mut Window,
12989        cx: &mut Context<Self>,
12990    ) {
12991        if self.take_rename(true, window, cx).is_some() {
12992            return;
12993        }
12994
12995        if self.mode.is_single_line() {
12996            cx.propagate();
12997            return;
12998        }
12999
13000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13001
13002        let text_layout_details = &self.text_layout_details(window);
13003
13004        self.change_selections(Default::default(), window, cx, |s| {
13005            s.move_with(|map, selection| {
13006                if !selection.is_empty() {
13007                    selection.goal = SelectionGoal::None;
13008                }
13009                let (cursor, goal) = movement::up_by_rows(
13010                    map,
13011                    selection.start,
13012                    action.lines,
13013                    selection.goal,
13014                    false,
13015                    text_layout_details,
13016                );
13017                selection.collapse_to(cursor, goal);
13018            });
13019        })
13020    }
13021
13022    pub fn move_down_by_lines(
13023        &mut self,
13024        action: &MoveDownByLines,
13025        window: &mut Window,
13026        cx: &mut Context<Self>,
13027    ) {
13028        if self.take_rename(true, window, cx).is_some() {
13029            return;
13030        }
13031
13032        if self.mode.is_single_line() {
13033            cx.propagate();
13034            return;
13035        }
13036
13037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13038
13039        let text_layout_details = &self.text_layout_details(window);
13040
13041        self.change_selections(Default::default(), window, cx, |s| {
13042            s.move_with(|map, selection| {
13043                if !selection.is_empty() {
13044                    selection.goal = SelectionGoal::None;
13045                }
13046                let (cursor, goal) = movement::down_by_rows(
13047                    map,
13048                    selection.start,
13049                    action.lines,
13050                    selection.goal,
13051                    false,
13052                    text_layout_details,
13053                );
13054                selection.collapse_to(cursor, goal);
13055            });
13056        })
13057    }
13058
13059    pub fn select_down_by_lines(
13060        &mut self,
13061        action: &SelectDownByLines,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13066        let text_layout_details = &self.text_layout_details(window);
13067        self.change_selections(Default::default(), window, cx, |s| {
13068            s.move_heads_with(|map, head, goal| {
13069                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13070            })
13071        })
13072    }
13073
13074    pub fn select_up_by_lines(
13075        &mut self,
13076        action: &SelectUpByLines,
13077        window: &mut Window,
13078        cx: &mut Context<Self>,
13079    ) {
13080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13081        let text_layout_details = &self.text_layout_details(window);
13082        self.change_selections(Default::default(), window, cx, |s| {
13083            s.move_heads_with(|map, head, goal| {
13084                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13085            })
13086        })
13087    }
13088
13089    pub fn select_page_up(
13090        &mut self,
13091        _: &SelectPageUp,
13092        window: &mut Window,
13093        cx: &mut Context<Self>,
13094    ) {
13095        let Some(row_count) = self.visible_row_count() else {
13096            return;
13097        };
13098
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100
13101        let text_layout_details = &self.text_layout_details(window);
13102
13103        self.change_selections(Default::default(), window, cx, |s| {
13104            s.move_heads_with(|map, head, goal| {
13105                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13106            })
13107        })
13108    }
13109
13110    pub fn move_page_up(
13111        &mut self,
13112        action: &MovePageUp,
13113        window: &mut Window,
13114        cx: &mut Context<Self>,
13115    ) {
13116        if self.take_rename(true, window, cx).is_some() {
13117            return;
13118        }
13119
13120        if self
13121            .context_menu
13122            .borrow_mut()
13123            .as_mut()
13124            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13125            .unwrap_or(false)
13126        {
13127            return;
13128        }
13129
13130        if matches!(self.mode, EditorMode::SingleLine) {
13131            cx.propagate();
13132            return;
13133        }
13134
13135        let Some(row_count) = self.visible_row_count() else {
13136            return;
13137        };
13138
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140
13141        let effects = if action.center_cursor {
13142            SelectionEffects::scroll(Autoscroll::center())
13143        } else {
13144            SelectionEffects::default()
13145        };
13146
13147        let text_layout_details = &self.text_layout_details(window);
13148
13149        self.change_selections(effects, window, cx, |s| {
13150            s.move_with(|map, selection| {
13151                if !selection.is_empty() {
13152                    selection.goal = SelectionGoal::None;
13153                }
13154                let (cursor, goal) = movement::up_by_rows(
13155                    map,
13156                    selection.end,
13157                    row_count,
13158                    selection.goal,
13159                    false,
13160                    text_layout_details,
13161                );
13162                selection.collapse_to(cursor, goal);
13163            });
13164        });
13165    }
13166
13167    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13169        let text_layout_details = &self.text_layout_details(window);
13170        self.change_selections(Default::default(), window, cx, |s| {
13171            s.move_heads_with(|map, head, goal| {
13172                movement::up(map, head, goal, false, text_layout_details)
13173            })
13174        })
13175    }
13176
13177    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13178        self.take_rename(true, window, cx);
13179
13180        if self.mode.is_single_line() {
13181            cx.propagate();
13182            return;
13183        }
13184
13185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13186
13187        let text_layout_details = &self.text_layout_details(window);
13188        let selection_count = self.selections.count();
13189        let first_selection = self.selections.first_anchor();
13190
13191        self.change_selections(Default::default(), window, cx, |s| {
13192            s.move_with(|map, selection| {
13193                if !selection.is_empty() {
13194                    selection.goal = SelectionGoal::None;
13195                }
13196                let (cursor, goal) = movement::down(
13197                    map,
13198                    selection.end,
13199                    selection.goal,
13200                    false,
13201                    text_layout_details,
13202                );
13203                selection.collapse_to(cursor, goal);
13204            });
13205        });
13206
13207        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13208        {
13209            cx.propagate();
13210        }
13211    }
13212
13213    pub fn select_page_down(
13214        &mut self,
13215        _: &SelectPageDown,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        let Some(row_count) = self.visible_row_count() else {
13220            return;
13221        };
13222
13223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13224
13225        let text_layout_details = &self.text_layout_details(window);
13226
13227        self.change_selections(Default::default(), window, cx, |s| {
13228            s.move_heads_with(|map, head, goal| {
13229                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13230            })
13231        })
13232    }
13233
13234    pub fn move_page_down(
13235        &mut self,
13236        action: &MovePageDown,
13237        window: &mut Window,
13238        cx: &mut Context<Self>,
13239    ) {
13240        if self.take_rename(true, window, cx).is_some() {
13241            return;
13242        }
13243
13244        if self
13245            .context_menu
13246            .borrow_mut()
13247            .as_mut()
13248            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13249            .unwrap_or(false)
13250        {
13251            return;
13252        }
13253
13254        if matches!(self.mode, EditorMode::SingleLine) {
13255            cx.propagate();
13256            return;
13257        }
13258
13259        let Some(row_count) = self.visible_row_count() else {
13260            return;
13261        };
13262
13263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13264
13265        let effects = if action.center_cursor {
13266            SelectionEffects::scroll(Autoscroll::center())
13267        } else {
13268            SelectionEffects::default()
13269        };
13270
13271        let text_layout_details = &self.text_layout_details(window);
13272        self.change_selections(effects, window, cx, |s| {
13273            s.move_with(|map, selection| {
13274                if !selection.is_empty() {
13275                    selection.goal = SelectionGoal::None;
13276                }
13277                let (cursor, goal) = movement::down_by_rows(
13278                    map,
13279                    selection.end,
13280                    row_count,
13281                    selection.goal,
13282                    false,
13283                    text_layout_details,
13284                );
13285                selection.collapse_to(cursor, goal);
13286            });
13287        });
13288    }
13289
13290    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13292        let text_layout_details = &self.text_layout_details(window);
13293        self.change_selections(Default::default(), window, cx, |s| {
13294            s.move_heads_with(|map, head, goal| {
13295                movement::down(map, head, goal, false, text_layout_details)
13296            })
13297        });
13298    }
13299
13300    pub fn context_menu_first(
13301        &mut self,
13302        _: &ContextMenuFirst,
13303        window: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13307            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13308        }
13309    }
13310
13311    pub fn context_menu_prev(
13312        &mut self,
13313        _: &ContextMenuPrevious,
13314        window: &mut Window,
13315        cx: &mut Context<Self>,
13316    ) {
13317        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13318            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13319        }
13320    }
13321
13322    pub fn context_menu_next(
13323        &mut self,
13324        _: &ContextMenuNext,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13329            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13330        }
13331    }
13332
13333    pub fn context_menu_last(
13334        &mut self,
13335        _: &ContextMenuLast,
13336        window: &mut Window,
13337        cx: &mut Context<Self>,
13338    ) {
13339        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13340            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13341        }
13342    }
13343
13344    pub fn signature_help_prev(
13345        &mut self,
13346        _: &SignatureHelpPrevious,
13347        _: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        if let Some(popover) = self.signature_help_state.popover_mut() {
13351            if popover.current_signature == 0 {
13352                popover.current_signature = popover.signatures.len() - 1;
13353            } else {
13354                popover.current_signature -= 1;
13355            }
13356            cx.notify();
13357        }
13358    }
13359
13360    pub fn signature_help_next(
13361        &mut self,
13362        _: &SignatureHelpNext,
13363        _: &mut Window,
13364        cx: &mut Context<Self>,
13365    ) {
13366        if let Some(popover) = self.signature_help_state.popover_mut() {
13367            if popover.current_signature + 1 == popover.signatures.len() {
13368                popover.current_signature = 0;
13369            } else {
13370                popover.current_signature += 1;
13371            }
13372            cx.notify();
13373        }
13374    }
13375
13376    pub fn move_to_previous_word_start(
13377        &mut self,
13378        _: &MoveToPreviousWordStart,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383        self.change_selections(Default::default(), window, cx, |s| {
13384            s.move_cursors_with(|map, head, _| {
13385                (
13386                    movement::previous_word_start(map, head),
13387                    SelectionGoal::None,
13388                )
13389            });
13390        })
13391    }
13392
13393    pub fn move_to_previous_subword_start(
13394        &mut self,
13395        _: &MoveToPreviousSubwordStart,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13400        self.change_selections(Default::default(), window, cx, |s| {
13401            s.move_cursors_with(|map, head, _| {
13402                (
13403                    movement::previous_subword_start(map, head),
13404                    SelectionGoal::None,
13405                )
13406            });
13407        })
13408    }
13409
13410    pub fn select_to_previous_word_start(
13411        &mut self,
13412        _: &SelectToPreviousWordStart,
13413        window: &mut Window,
13414        cx: &mut Context<Self>,
13415    ) {
13416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13417        self.change_selections(Default::default(), window, cx, |s| {
13418            s.move_heads_with(|map, head, _| {
13419                (
13420                    movement::previous_word_start(map, head),
13421                    SelectionGoal::None,
13422                )
13423            });
13424        })
13425    }
13426
13427    pub fn select_to_previous_subword_start(
13428        &mut self,
13429        _: &SelectToPreviousSubwordStart,
13430        window: &mut Window,
13431        cx: &mut Context<Self>,
13432    ) {
13433        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13434        self.change_selections(Default::default(), window, cx, |s| {
13435            s.move_heads_with(|map, head, _| {
13436                (
13437                    movement::previous_subword_start(map, head),
13438                    SelectionGoal::None,
13439                )
13440            });
13441        })
13442    }
13443
13444    pub fn delete_to_previous_word_start(
13445        &mut self,
13446        action: &DeleteToPreviousWordStart,
13447        window: &mut Window,
13448        cx: &mut Context<Self>,
13449    ) {
13450        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13451        self.transact(window, cx, |this, window, cx| {
13452            this.select_autoclose_pair(window, cx);
13453            this.change_selections(Default::default(), window, cx, |s| {
13454                s.move_with(|map, selection| {
13455                    if selection.is_empty() {
13456                        let mut cursor = if action.ignore_newlines {
13457                            movement::previous_word_start(map, selection.head())
13458                        } else {
13459                            movement::previous_word_start_or_newline(map, selection.head())
13460                        };
13461                        cursor = movement::adjust_greedy_deletion(
13462                            map,
13463                            selection.head(),
13464                            cursor,
13465                            action.ignore_brackets,
13466                        );
13467                        selection.set_head(cursor, SelectionGoal::None);
13468                    }
13469                });
13470            });
13471            this.insert("", window, cx);
13472        });
13473    }
13474
13475    pub fn delete_to_previous_subword_start(
13476        &mut self,
13477        _: &DeleteToPreviousSubwordStart,
13478        window: &mut Window,
13479        cx: &mut Context<Self>,
13480    ) {
13481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13482        self.transact(window, cx, |this, window, cx| {
13483            this.select_autoclose_pair(window, cx);
13484            this.change_selections(Default::default(), window, cx, |s| {
13485                s.move_with(|map, selection| {
13486                    if selection.is_empty() {
13487                        let mut cursor = movement::previous_subword_start(map, selection.head());
13488                        cursor =
13489                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13490                        selection.set_head(cursor, SelectionGoal::None);
13491                    }
13492                });
13493            });
13494            this.insert("", window, cx);
13495        });
13496    }
13497
13498    pub fn move_to_next_word_end(
13499        &mut self,
13500        _: &MoveToNextWordEnd,
13501        window: &mut Window,
13502        cx: &mut Context<Self>,
13503    ) {
13504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13505        self.change_selections(Default::default(), window, cx, |s| {
13506            s.move_cursors_with(|map, head, _| {
13507                (movement::next_word_end(map, head), SelectionGoal::None)
13508            });
13509        })
13510    }
13511
13512    pub fn move_to_next_subword_end(
13513        &mut self,
13514        _: &MoveToNextSubwordEnd,
13515        window: &mut Window,
13516        cx: &mut Context<Self>,
13517    ) {
13518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13519        self.change_selections(Default::default(), window, cx, |s| {
13520            s.move_cursors_with(|map, head, _| {
13521                (movement::next_subword_end(map, head), SelectionGoal::None)
13522            });
13523        })
13524    }
13525
13526    pub fn select_to_next_word_end(
13527        &mut self,
13528        _: &SelectToNextWordEnd,
13529        window: &mut Window,
13530        cx: &mut Context<Self>,
13531    ) {
13532        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13533        self.change_selections(Default::default(), window, cx, |s| {
13534            s.move_heads_with(|map, head, _| {
13535                (movement::next_word_end(map, head), SelectionGoal::None)
13536            });
13537        })
13538    }
13539
13540    pub fn select_to_next_subword_end(
13541        &mut self,
13542        _: &SelectToNextSubwordEnd,
13543        window: &mut Window,
13544        cx: &mut Context<Self>,
13545    ) {
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13547        self.change_selections(Default::default(), window, cx, |s| {
13548            s.move_heads_with(|map, head, _| {
13549                (movement::next_subword_end(map, head), SelectionGoal::None)
13550            });
13551        })
13552    }
13553
13554    pub fn delete_to_next_word_end(
13555        &mut self,
13556        action: &DeleteToNextWordEnd,
13557        window: &mut Window,
13558        cx: &mut Context<Self>,
13559    ) {
13560        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13561        self.transact(window, cx, |this, window, cx| {
13562            this.change_selections(Default::default(), window, cx, |s| {
13563                s.move_with(|map, selection| {
13564                    if selection.is_empty() {
13565                        let mut cursor = if action.ignore_newlines {
13566                            movement::next_word_end(map, selection.head())
13567                        } else {
13568                            movement::next_word_end_or_newline(map, selection.head())
13569                        };
13570                        cursor = movement::adjust_greedy_deletion(
13571                            map,
13572                            selection.head(),
13573                            cursor,
13574                            action.ignore_brackets,
13575                        );
13576                        selection.set_head(cursor, SelectionGoal::None);
13577                    }
13578                });
13579            });
13580            this.insert("", window, cx);
13581        });
13582    }
13583
13584    pub fn delete_to_next_subword_end(
13585        &mut self,
13586        _: &DeleteToNextSubwordEnd,
13587        window: &mut Window,
13588        cx: &mut Context<Self>,
13589    ) {
13590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13591        self.transact(window, cx, |this, window, cx| {
13592            this.change_selections(Default::default(), window, cx, |s| {
13593                s.move_with(|map, selection| {
13594                    if selection.is_empty() {
13595                        let mut cursor = movement::next_subword_end(map, selection.head());
13596                        cursor =
13597                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13598                        selection.set_head(cursor, SelectionGoal::None);
13599                    }
13600                });
13601            });
13602            this.insert("", window, cx);
13603        });
13604    }
13605
13606    pub fn move_to_beginning_of_line(
13607        &mut self,
13608        action: &MoveToBeginningOfLine,
13609        window: &mut Window,
13610        cx: &mut Context<Self>,
13611    ) {
13612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13613        self.change_selections(Default::default(), window, cx, |s| {
13614            s.move_cursors_with(|map, head, _| {
13615                (
13616                    movement::indented_line_beginning(
13617                        map,
13618                        head,
13619                        action.stop_at_soft_wraps,
13620                        action.stop_at_indent,
13621                    ),
13622                    SelectionGoal::None,
13623                )
13624            });
13625        })
13626    }
13627
13628    pub fn select_to_beginning_of_line(
13629        &mut self,
13630        action: &SelectToBeginningOfLine,
13631        window: &mut Window,
13632        cx: &mut Context<Self>,
13633    ) {
13634        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13635        self.change_selections(Default::default(), window, cx, |s| {
13636            s.move_heads_with(|map, head, _| {
13637                (
13638                    movement::indented_line_beginning(
13639                        map,
13640                        head,
13641                        action.stop_at_soft_wraps,
13642                        action.stop_at_indent,
13643                    ),
13644                    SelectionGoal::None,
13645                )
13646            });
13647        });
13648    }
13649
13650    pub fn delete_to_beginning_of_line(
13651        &mut self,
13652        action: &DeleteToBeginningOfLine,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13657        self.transact(window, cx, |this, window, cx| {
13658            this.change_selections(Default::default(), window, cx, |s| {
13659                s.move_with(|_, selection| {
13660                    selection.reversed = true;
13661                });
13662            });
13663
13664            this.select_to_beginning_of_line(
13665                &SelectToBeginningOfLine {
13666                    stop_at_soft_wraps: false,
13667                    stop_at_indent: action.stop_at_indent,
13668                },
13669                window,
13670                cx,
13671            );
13672            this.backspace(&Backspace, window, cx);
13673        });
13674    }
13675
13676    pub fn move_to_end_of_line(
13677        &mut self,
13678        action: &MoveToEndOfLine,
13679        window: &mut Window,
13680        cx: &mut Context<Self>,
13681    ) {
13682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13683        self.change_selections(Default::default(), window, cx, |s| {
13684            s.move_cursors_with(|map, head, _| {
13685                (
13686                    movement::line_end(map, head, action.stop_at_soft_wraps),
13687                    SelectionGoal::None,
13688                )
13689            });
13690        })
13691    }
13692
13693    pub fn select_to_end_of_line(
13694        &mut self,
13695        action: &SelectToEndOfLine,
13696        window: &mut Window,
13697        cx: &mut Context<Self>,
13698    ) {
13699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13700        self.change_selections(Default::default(), window, cx, |s| {
13701            s.move_heads_with(|map, head, _| {
13702                (
13703                    movement::line_end(map, head, action.stop_at_soft_wraps),
13704                    SelectionGoal::None,
13705                )
13706            });
13707        })
13708    }
13709
13710    pub fn delete_to_end_of_line(
13711        &mut self,
13712        _: &DeleteToEndOfLine,
13713        window: &mut Window,
13714        cx: &mut Context<Self>,
13715    ) {
13716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13717        self.transact(window, cx, |this, window, cx| {
13718            this.select_to_end_of_line(
13719                &SelectToEndOfLine {
13720                    stop_at_soft_wraps: false,
13721                },
13722                window,
13723                cx,
13724            );
13725            this.delete(&Delete, window, cx);
13726        });
13727    }
13728
13729    pub fn cut_to_end_of_line(
13730        &mut self,
13731        action: &CutToEndOfLine,
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            if !action.stop_at_newlines {
13745                this.change_selections(Default::default(), window, cx, |s| {
13746                    s.move_with(|_, sel| {
13747                        if sel.is_empty() {
13748                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13749                        }
13750                    });
13751                });
13752            }
13753            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13754            let item = this.cut_common(false, window, cx);
13755            cx.write_to_clipboard(item);
13756        });
13757    }
13758
13759    pub fn move_to_start_of_paragraph(
13760        &mut self,
13761        _: &MoveToStartOfParagraph,
13762        window: &mut Window,
13763        cx: &mut Context<Self>,
13764    ) {
13765        if matches!(self.mode, EditorMode::SingleLine) {
13766            cx.propagate();
13767            return;
13768        }
13769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13770        self.change_selections(Default::default(), window, cx, |s| {
13771            s.move_with(|map, selection| {
13772                selection.collapse_to(
13773                    movement::start_of_paragraph(map, selection.head(), 1),
13774                    SelectionGoal::None,
13775                )
13776            });
13777        })
13778    }
13779
13780    pub fn move_to_end_of_paragraph(
13781        &mut self,
13782        _: &MoveToEndOfParagraph,
13783        window: &mut Window,
13784        cx: &mut Context<Self>,
13785    ) {
13786        if matches!(self.mode, EditorMode::SingleLine) {
13787            cx.propagate();
13788            return;
13789        }
13790        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13791        self.change_selections(Default::default(), window, cx, |s| {
13792            s.move_with(|map, selection| {
13793                selection.collapse_to(
13794                    movement::end_of_paragraph(map, selection.head(), 1),
13795                    SelectionGoal::None,
13796                )
13797            });
13798        })
13799    }
13800
13801    pub fn select_to_start_of_paragraph(
13802        &mut self,
13803        _: &SelectToStartOfParagraph,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) {
13807        if matches!(self.mode, EditorMode::SingleLine) {
13808            cx.propagate();
13809            return;
13810        }
13811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13812        self.change_selections(Default::default(), window, cx, |s| {
13813            s.move_heads_with(|map, head, _| {
13814                (
13815                    movement::start_of_paragraph(map, head, 1),
13816                    SelectionGoal::None,
13817                )
13818            });
13819        })
13820    }
13821
13822    pub fn select_to_end_of_paragraph(
13823        &mut self,
13824        _: &SelectToEndOfParagraph,
13825        window: &mut Window,
13826        cx: &mut Context<Self>,
13827    ) {
13828        if matches!(self.mode, EditorMode::SingleLine) {
13829            cx.propagate();
13830            return;
13831        }
13832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13833        self.change_selections(Default::default(), window, cx, |s| {
13834            s.move_heads_with(|map, head, _| {
13835                (
13836                    movement::end_of_paragraph(map, head, 1),
13837                    SelectionGoal::None,
13838                )
13839            });
13840        })
13841    }
13842
13843    pub fn move_to_start_of_excerpt(
13844        &mut self,
13845        _: &MoveToStartOfExcerpt,
13846        window: &mut Window,
13847        cx: &mut Context<Self>,
13848    ) {
13849        if matches!(self.mode, EditorMode::SingleLine) {
13850            cx.propagate();
13851            return;
13852        }
13853        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13854        self.change_selections(Default::default(), window, cx, |s| {
13855            s.move_with(|map, selection| {
13856                selection.collapse_to(
13857                    movement::start_of_excerpt(
13858                        map,
13859                        selection.head(),
13860                        workspace::searchable::Direction::Prev,
13861                    ),
13862                    SelectionGoal::None,
13863                )
13864            });
13865        })
13866    }
13867
13868    pub fn move_to_start_of_next_excerpt(
13869        &mut self,
13870        _: &MoveToStartOfNextExcerpt,
13871        window: &mut Window,
13872        cx: &mut Context<Self>,
13873    ) {
13874        if matches!(self.mode, EditorMode::SingleLine) {
13875            cx.propagate();
13876            return;
13877        }
13878
13879        self.change_selections(Default::default(), window, cx, |s| {
13880            s.move_with(|map, selection| {
13881                selection.collapse_to(
13882                    movement::start_of_excerpt(
13883                        map,
13884                        selection.head(),
13885                        workspace::searchable::Direction::Next,
13886                    ),
13887                    SelectionGoal::None,
13888                )
13889            });
13890        })
13891    }
13892
13893    pub fn move_to_end_of_excerpt(
13894        &mut self,
13895        _: &MoveToEndOfExcerpt,
13896        window: &mut Window,
13897        cx: &mut Context<Self>,
13898    ) {
13899        if matches!(self.mode, EditorMode::SingleLine) {
13900            cx.propagate();
13901            return;
13902        }
13903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13904        self.change_selections(Default::default(), window, cx, |s| {
13905            s.move_with(|map, selection| {
13906                selection.collapse_to(
13907                    movement::end_of_excerpt(
13908                        map,
13909                        selection.head(),
13910                        workspace::searchable::Direction::Next,
13911                    ),
13912                    SelectionGoal::None,
13913                )
13914            });
13915        })
13916    }
13917
13918    pub fn move_to_end_of_previous_excerpt(
13919        &mut self,
13920        _: &MoveToEndOfPreviousExcerpt,
13921        window: &mut Window,
13922        cx: &mut Context<Self>,
13923    ) {
13924        if matches!(self.mode, EditorMode::SingleLine) {
13925            cx.propagate();
13926            return;
13927        }
13928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13929        self.change_selections(Default::default(), window, cx, |s| {
13930            s.move_with(|map, selection| {
13931                selection.collapse_to(
13932                    movement::end_of_excerpt(
13933                        map,
13934                        selection.head(),
13935                        workspace::searchable::Direction::Prev,
13936                    ),
13937                    SelectionGoal::None,
13938                )
13939            });
13940        })
13941    }
13942
13943    pub fn select_to_start_of_excerpt(
13944        &mut self,
13945        _: &SelectToStartOfExcerpt,
13946        window: &mut Window,
13947        cx: &mut Context<Self>,
13948    ) {
13949        if matches!(self.mode, EditorMode::SingleLine) {
13950            cx.propagate();
13951            return;
13952        }
13953        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13954        self.change_selections(Default::default(), window, cx, |s| {
13955            s.move_heads_with(|map, head, _| {
13956                (
13957                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13958                    SelectionGoal::None,
13959                )
13960            });
13961        })
13962    }
13963
13964    pub fn select_to_start_of_next_excerpt(
13965        &mut self,
13966        _: &SelectToStartOfNextExcerpt,
13967        window: &mut Window,
13968        cx: &mut Context<Self>,
13969    ) {
13970        if matches!(self.mode, EditorMode::SingleLine) {
13971            cx.propagate();
13972            return;
13973        }
13974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13975        self.change_selections(Default::default(), window, cx, |s| {
13976            s.move_heads_with(|map, head, _| {
13977                (
13978                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13979                    SelectionGoal::None,
13980                )
13981            });
13982        })
13983    }
13984
13985    pub fn select_to_end_of_excerpt(
13986        &mut self,
13987        _: &SelectToEndOfExcerpt,
13988        window: &mut Window,
13989        cx: &mut Context<Self>,
13990    ) {
13991        if matches!(self.mode, EditorMode::SingleLine) {
13992            cx.propagate();
13993            return;
13994        }
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        self.change_selections(Default::default(), window, cx, |s| {
13997            s.move_heads_with(|map, head, _| {
13998                (
13999                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14000                    SelectionGoal::None,
14001                )
14002            });
14003        })
14004    }
14005
14006    pub fn select_to_end_of_previous_excerpt(
14007        &mut self,
14008        _: &SelectToEndOfPreviousExcerpt,
14009        window: &mut Window,
14010        cx: &mut Context<Self>,
14011    ) {
14012        if matches!(self.mode, EditorMode::SingleLine) {
14013            cx.propagate();
14014            return;
14015        }
14016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14017        self.change_selections(Default::default(), window, cx, |s| {
14018            s.move_heads_with(|map, head, _| {
14019                (
14020                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14021                    SelectionGoal::None,
14022                )
14023            });
14024        })
14025    }
14026
14027    pub fn move_to_beginning(
14028        &mut self,
14029        _: &MoveToBeginning,
14030        window: &mut Window,
14031        cx: &mut Context<Self>,
14032    ) {
14033        if matches!(self.mode, EditorMode::SingleLine) {
14034            cx.propagate();
14035            return;
14036        }
14037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14038        self.change_selections(Default::default(), window, cx, |s| {
14039            s.select_ranges(vec![0..0]);
14040        });
14041    }
14042
14043    pub fn select_to_beginning(
14044        &mut self,
14045        _: &SelectToBeginning,
14046        window: &mut Window,
14047        cx: &mut Context<Self>,
14048    ) {
14049        let mut selection = self.selections.last::<Point>(cx);
14050        selection.set_head(Point::zero(), SelectionGoal::None);
14051        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14052        self.change_selections(Default::default(), window, cx, |s| {
14053            s.select(vec![selection]);
14054        });
14055    }
14056
14057    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14058        if matches!(self.mode, EditorMode::SingleLine) {
14059            cx.propagate();
14060            return;
14061        }
14062        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14063        let cursor = self.buffer.read(cx).read(cx).len();
14064        self.change_selections(Default::default(), window, cx, |s| {
14065            s.select_ranges(vec![cursor..cursor])
14066        });
14067    }
14068
14069    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14070        self.nav_history = nav_history;
14071    }
14072
14073    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14074        self.nav_history.as_ref()
14075    }
14076
14077    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14078        self.push_to_nav_history(
14079            self.selections.newest_anchor().head(),
14080            None,
14081            false,
14082            true,
14083            cx,
14084        );
14085    }
14086
14087    fn push_to_nav_history(
14088        &mut self,
14089        cursor_anchor: Anchor,
14090        new_position: Option<Point>,
14091        is_deactivate: bool,
14092        always: bool,
14093        cx: &mut Context<Self>,
14094    ) {
14095        if let Some(nav_history) = self.nav_history.as_mut() {
14096            let buffer = self.buffer.read(cx).read(cx);
14097            let cursor_position = cursor_anchor.to_point(&buffer);
14098            let scroll_state = self.scroll_manager.anchor();
14099            let scroll_top_row = scroll_state.top_row(&buffer);
14100            drop(buffer);
14101
14102            if let Some(new_position) = new_position {
14103                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14104                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14105                    return;
14106                }
14107            }
14108
14109            nav_history.push(
14110                Some(NavigationData {
14111                    cursor_anchor,
14112                    cursor_position,
14113                    scroll_anchor: scroll_state,
14114                    scroll_top_row,
14115                }),
14116                cx,
14117            );
14118            cx.emit(EditorEvent::PushedToNavHistory {
14119                anchor: cursor_anchor,
14120                is_deactivate,
14121            })
14122        }
14123    }
14124
14125    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14127        let buffer = self.buffer.read(cx).snapshot(cx);
14128        let mut selection = self.selections.first::<usize>(cx);
14129        selection.set_head(buffer.len(), SelectionGoal::None);
14130        self.change_selections(Default::default(), window, cx, |s| {
14131            s.select(vec![selection]);
14132        });
14133    }
14134
14135    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14137        let end = self.buffer.read(cx).read(cx).len();
14138        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14139            s.select_ranges(vec![0..end]);
14140        });
14141    }
14142
14143    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14144        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14145        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14146        let mut selections = self.selections.all::<Point>(cx);
14147        let max_point = display_map.buffer_snapshot().max_point();
14148        for selection in &mut selections {
14149            let rows = selection.spanned_rows(true, &display_map);
14150            selection.start = Point::new(rows.start.0, 0);
14151            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14152            selection.reversed = false;
14153        }
14154        self.change_selections(Default::default(), window, cx, |s| {
14155            s.select(selections);
14156        });
14157    }
14158
14159    pub fn split_selection_into_lines(
14160        &mut self,
14161        action: &SplitSelectionIntoLines,
14162        window: &mut Window,
14163        cx: &mut Context<Self>,
14164    ) {
14165        let selections = self
14166            .selections
14167            .all::<Point>(cx)
14168            .into_iter()
14169            .map(|selection| selection.start..selection.end)
14170            .collect::<Vec<_>>();
14171        self.unfold_ranges(&selections, true, true, cx);
14172
14173        let mut new_selection_ranges = Vec::new();
14174        {
14175            let buffer = self.buffer.read(cx).read(cx);
14176            for selection in selections {
14177                for row in selection.start.row..selection.end.row {
14178                    let line_start = Point::new(row, 0);
14179                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14180
14181                    if action.keep_selections {
14182                        // Keep the selection range for each line
14183                        let selection_start = if row == selection.start.row {
14184                            selection.start
14185                        } else {
14186                            line_start
14187                        };
14188                        new_selection_ranges.push(selection_start..line_end);
14189                    } else {
14190                        // Collapse to cursor at end of line
14191                        new_selection_ranges.push(line_end..line_end);
14192                    }
14193                }
14194
14195                let is_multiline_selection = selection.start.row != selection.end.row;
14196                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14197                // so this action feels more ergonomic when paired with other selection operations
14198                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14199                if !should_skip_last {
14200                    if action.keep_selections {
14201                        if is_multiline_selection {
14202                            let line_start = Point::new(selection.end.row, 0);
14203                            new_selection_ranges.push(line_start..selection.end);
14204                        } else {
14205                            new_selection_ranges.push(selection.start..selection.end);
14206                        }
14207                    } else {
14208                        new_selection_ranges.push(selection.end..selection.end);
14209                    }
14210                }
14211            }
14212        }
14213        self.change_selections(Default::default(), window, cx, |s| {
14214            s.select_ranges(new_selection_ranges);
14215        });
14216    }
14217
14218    pub fn add_selection_above(
14219        &mut self,
14220        action: &AddSelectionAbove,
14221        window: &mut Window,
14222        cx: &mut Context<Self>,
14223    ) {
14224        self.add_selection(true, action.skip_soft_wrap, window, cx);
14225    }
14226
14227    pub fn add_selection_below(
14228        &mut self,
14229        action: &AddSelectionBelow,
14230        window: &mut Window,
14231        cx: &mut Context<Self>,
14232    ) {
14233        self.add_selection(false, action.skip_soft_wrap, window, cx);
14234    }
14235
14236    fn add_selection(
14237        &mut self,
14238        above: bool,
14239        skip_soft_wrap: bool,
14240        window: &mut Window,
14241        cx: &mut Context<Self>,
14242    ) {
14243        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14244
14245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14246        let all_selections = self.selections.all::<Point>(cx);
14247        let text_layout_details = self.text_layout_details(window);
14248
14249        let (mut columnar_selections, new_selections_to_columnarize) = {
14250            if let Some(state) = self.add_selections_state.as_ref() {
14251                let columnar_selection_ids: HashSet<_> = state
14252                    .groups
14253                    .iter()
14254                    .flat_map(|group| group.stack.iter())
14255                    .copied()
14256                    .collect();
14257
14258                all_selections
14259                    .into_iter()
14260                    .partition(|s| columnar_selection_ids.contains(&s.id))
14261            } else {
14262                (Vec::new(), all_selections)
14263            }
14264        };
14265
14266        let mut state = self
14267            .add_selections_state
14268            .take()
14269            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14270
14271        for selection in new_selections_to_columnarize {
14272            let range = selection.display_range(&display_map).sorted();
14273            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14274            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14275            let positions = start_x.min(end_x)..start_x.max(end_x);
14276            let mut stack = Vec::new();
14277            for row in range.start.row().0..=range.end.row().0 {
14278                if let Some(selection) = self.selections.build_columnar_selection(
14279                    &display_map,
14280                    DisplayRow(row),
14281                    &positions,
14282                    selection.reversed,
14283                    &text_layout_details,
14284                ) {
14285                    stack.push(selection.id);
14286                    columnar_selections.push(selection);
14287                }
14288            }
14289            if !stack.is_empty() {
14290                if above {
14291                    stack.reverse();
14292                }
14293                state.groups.push(AddSelectionsGroup { above, stack });
14294            }
14295        }
14296
14297        let mut final_selections = Vec::new();
14298        let end_row = if above {
14299            DisplayRow(0)
14300        } else {
14301            display_map.max_point().row()
14302        };
14303
14304        let mut last_added_item_per_group = HashMap::default();
14305        for group in state.groups.iter_mut() {
14306            if let Some(last_id) = group.stack.last() {
14307                last_added_item_per_group.insert(*last_id, group);
14308            }
14309        }
14310
14311        for selection in columnar_selections {
14312            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14313                if above == group.above {
14314                    let range = selection.display_range(&display_map).sorted();
14315                    debug_assert_eq!(range.start.row(), range.end.row());
14316                    let mut row = range.start.row();
14317                    let positions =
14318                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14319                            Pixels::from(start)..Pixels::from(end)
14320                        } else {
14321                            let start_x =
14322                                display_map.x_for_display_point(range.start, &text_layout_details);
14323                            let end_x =
14324                                display_map.x_for_display_point(range.end, &text_layout_details);
14325                            start_x.min(end_x)..start_x.max(end_x)
14326                        };
14327
14328                    let mut maybe_new_selection = None;
14329                    let direction = if above { -1 } else { 1 };
14330
14331                    while row != end_row {
14332                        if skip_soft_wrap {
14333                            row = display_map
14334                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14335                                .row();
14336                        } else if above {
14337                            row.0 -= 1;
14338                        } else {
14339                            row.0 += 1;
14340                        }
14341
14342                        if let Some(new_selection) = self.selections.build_columnar_selection(
14343                            &display_map,
14344                            row,
14345                            &positions,
14346                            selection.reversed,
14347                            &text_layout_details,
14348                        ) {
14349                            maybe_new_selection = Some(new_selection);
14350                            break;
14351                        }
14352                    }
14353
14354                    if let Some(new_selection) = maybe_new_selection {
14355                        group.stack.push(new_selection.id);
14356                        if above {
14357                            final_selections.push(new_selection);
14358                            final_selections.push(selection);
14359                        } else {
14360                            final_selections.push(selection);
14361                            final_selections.push(new_selection);
14362                        }
14363                    } else {
14364                        final_selections.push(selection);
14365                    }
14366                } else {
14367                    group.stack.pop();
14368                }
14369            } else {
14370                final_selections.push(selection);
14371            }
14372        }
14373
14374        self.change_selections(Default::default(), window, cx, |s| {
14375            s.select(final_selections);
14376        });
14377
14378        let final_selection_ids: HashSet<_> = self
14379            .selections
14380            .all::<Point>(cx)
14381            .iter()
14382            .map(|s| s.id)
14383            .collect();
14384        state.groups.retain_mut(|group| {
14385            // selections might get merged above so we remove invalid items from stacks
14386            group.stack.retain(|id| final_selection_ids.contains(id));
14387
14388            // single selection in stack can be treated as initial state
14389            group.stack.len() > 1
14390        });
14391
14392        if !state.groups.is_empty() {
14393            self.add_selections_state = Some(state);
14394        }
14395    }
14396
14397    fn select_match_ranges(
14398        &mut self,
14399        range: Range<usize>,
14400        reversed: bool,
14401        replace_newest: bool,
14402        auto_scroll: Option<Autoscroll>,
14403        window: &mut Window,
14404        cx: &mut Context<Editor>,
14405    ) {
14406        self.unfold_ranges(
14407            std::slice::from_ref(&range),
14408            false,
14409            auto_scroll.is_some(),
14410            cx,
14411        );
14412        let effects = if let Some(scroll) = auto_scroll {
14413            SelectionEffects::scroll(scroll)
14414        } else {
14415            SelectionEffects::no_scroll()
14416        };
14417        self.change_selections(effects, window, cx, |s| {
14418            if replace_newest {
14419                s.delete(s.newest_anchor().id);
14420            }
14421            if reversed {
14422                s.insert_range(range.end..range.start);
14423            } else {
14424                s.insert_range(range);
14425            }
14426        });
14427    }
14428
14429    pub fn select_next_match_internal(
14430        &mut self,
14431        display_map: &DisplaySnapshot,
14432        replace_newest: bool,
14433        autoscroll: Option<Autoscroll>,
14434        window: &mut Window,
14435        cx: &mut Context<Self>,
14436    ) -> Result<()> {
14437        let buffer = display_map.buffer_snapshot();
14438        let mut selections = self.selections.all::<usize>(cx);
14439        if let Some(mut select_next_state) = self.select_next_state.take() {
14440            let query = &select_next_state.query;
14441            if !select_next_state.done {
14442                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14443                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14444                let mut next_selected_range = None;
14445
14446                // Collect and sort selection ranges for efficient overlap checking
14447                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14448                selection_ranges.sort_by_key(|r| r.start);
14449
14450                let bytes_after_last_selection =
14451                    buffer.bytes_in_range(last_selection.end..buffer.len());
14452                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14453                let query_matches = query
14454                    .stream_find_iter(bytes_after_last_selection)
14455                    .map(|result| (last_selection.end, result))
14456                    .chain(
14457                        query
14458                            .stream_find_iter(bytes_before_first_selection)
14459                            .map(|result| (0, result)),
14460                    );
14461
14462                for (start_offset, query_match) in query_matches {
14463                    let query_match = query_match.unwrap(); // can only fail due to I/O
14464                    let offset_range =
14465                        start_offset + query_match.start()..start_offset + query_match.end();
14466
14467                    if !select_next_state.wordwise
14468                        || (!buffer.is_inside_word(offset_range.start, None)
14469                            && !buffer.is_inside_word(offset_range.end, None))
14470                    {
14471                        // Use binary search to check for overlap (O(log n))
14472                        let overlaps = selection_ranges
14473                            .binary_search_by(|range| {
14474                                if range.end <= offset_range.start {
14475                                    std::cmp::Ordering::Less
14476                                } else if range.start >= offset_range.end {
14477                                    std::cmp::Ordering::Greater
14478                                } else {
14479                                    std::cmp::Ordering::Equal
14480                                }
14481                            })
14482                            .is_ok();
14483
14484                        if !overlaps {
14485                            next_selected_range = Some(offset_range);
14486                            break;
14487                        }
14488                    }
14489                }
14490
14491                if let Some(next_selected_range) = next_selected_range {
14492                    self.select_match_ranges(
14493                        next_selected_range,
14494                        last_selection.reversed,
14495                        replace_newest,
14496                        autoscroll,
14497                        window,
14498                        cx,
14499                    );
14500                } else {
14501                    select_next_state.done = true;
14502                }
14503            }
14504
14505            self.select_next_state = Some(select_next_state);
14506        } else {
14507            let mut only_carets = true;
14508            let mut same_text_selected = true;
14509            let mut selected_text = None;
14510
14511            let mut selections_iter = selections.iter().peekable();
14512            while let Some(selection) = selections_iter.next() {
14513                if selection.start != selection.end {
14514                    only_carets = false;
14515                }
14516
14517                if same_text_selected {
14518                    if selected_text.is_none() {
14519                        selected_text =
14520                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14521                    }
14522
14523                    if let Some(next_selection) = selections_iter.peek() {
14524                        if next_selection.range().len() == selection.range().len() {
14525                            let next_selected_text = buffer
14526                                .text_for_range(next_selection.range())
14527                                .collect::<String>();
14528                            if Some(next_selected_text) != selected_text {
14529                                same_text_selected = false;
14530                                selected_text = None;
14531                            }
14532                        } else {
14533                            same_text_selected = false;
14534                            selected_text = None;
14535                        }
14536                    }
14537                }
14538            }
14539
14540            if only_carets {
14541                for selection in &mut selections {
14542                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14543                    selection.start = word_range.start;
14544                    selection.end = word_range.end;
14545                    selection.goal = SelectionGoal::None;
14546                    selection.reversed = false;
14547                    self.select_match_ranges(
14548                        selection.start..selection.end,
14549                        selection.reversed,
14550                        replace_newest,
14551                        autoscroll,
14552                        window,
14553                        cx,
14554                    );
14555                }
14556
14557                if selections.len() == 1 {
14558                    let selection = selections
14559                        .last()
14560                        .expect("ensured that there's only one selection");
14561                    let query = buffer
14562                        .text_for_range(selection.start..selection.end)
14563                        .collect::<String>();
14564                    let is_empty = query.is_empty();
14565                    let select_state = SelectNextState {
14566                        query: AhoCorasick::new(&[query])?,
14567                        wordwise: true,
14568                        done: is_empty,
14569                    };
14570                    self.select_next_state = Some(select_state);
14571                } else {
14572                    self.select_next_state = None;
14573                }
14574            } else if let Some(selected_text) = selected_text {
14575                self.select_next_state = Some(SelectNextState {
14576                    query: AhoCorasick::new(&[selected_text])?,
14577                    wordwise: false,
14578                    done: false,
14579                });
14580                self.select_next_match_internal(
14581                    display_map,
14582                    replace_newest,
14583                    autoscroll,
14584                    window,
14585                    cx,
14586                )?;
14587            }
14588        }
14589        Ok(())
14590    }
14591
14592    pub fn select_all_matches(
14593        &mut self,
14594        _action: &SelectAllMatches,
14595        window: &mut Window,
14596        cx: &mut Context<Self>,
14597    ) -> Result<()> {
14598        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14599
14600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14601
14602        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14603        let Some(select_next_state) = self.select_next_state.as_mut() else {
14604            return Ok(());
14605        };
14606        if select_next_state.done {
14607            return Ok(());
14608        }
14609
14610        let mut new_selections = Vec::new();
14611
14612        let reversed = self.selections.oldest::<usize>(cx).reversed;
14613        let buffer = display_map.buffer_snapshot();
14614        let query_matches = select_next_state
14615            .query
14616            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14617
14618        for query_match in query_matches.into_iter() {
14619            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14620            let offset_range = if reversed {
14621                query_match.end()..query_match.start()
14622            } else {
14623                query_match.start()..query_match.end()
14624            };
14625
14626            if !select_next_state.wordwise
14627                || (!buffer.is_inside_word(offset_range.start, None)
14628                    && !buffer.is_inside_word(offset_range.end, None))
14629            {
14630                new_selections.push(offset_range.start..offset_range.end);
14631            }
14632        }
14633
14634        select_next_state.done = true;
14635
14636        if new_selections.is_empty() {
14637            log::error!("bug: new_selections is empty in select_all_matches");
14638            return Ok(());
14639        }
14640
14641        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14642        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14643            selections.select_ranges(new_selections)
14644        });
14645
14646        Ok(())
14647    }
14648
14649    pub fn select_next(
14650        &mut self,
14651        action: &SelectNext,
14652        window: &mut Window,
14653        cx: &mut Context<Self>,
14654    ) -> Result<()> {
14655        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14656        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14657        self.select_next_match_internal(
14658            &display_map,
14659            action.replace_newest,
14660            Some(Autoscroll::newest()),
14661            window,
14662            cx,
14663        )?;
14664        Ok(())
14665    }
14666
14667    pub fn select_previous(
14668        &mut self,
14669        action: &SelectPrevious,
14670        window: &mut Window,
14671        cx: &mut Context<Self>,
14672    ) -> Result<()> {
14673        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14674        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14675        let buffer = display_map.buffer_snapshot();
14676        let mut selections = self.selections.all::<usize>(cx);
14677        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14678            let query = &select_prev_state.query;
14679            if !select_prev_state.done {
14680                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14681                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14682                let mut next_selected_range = None;
14683                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14684                let bytes_before_last_selection =
14685                    buffer.reversed_bytes_in_range(0..last_selection.start);
14686                let bytes_after_first_selection =
14687                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14688                let query_matches = query
14689                    .stream_find_iter(bytes_before_last_selection)
14690                    .map(|result| (last_selection.start, result))
14691                    .chain(
14692                        query
14693                            .stream_find_iter(bytes_after_first_selection)
14694                            .map(|result| (buffer.len(), result)),
14695                    );
14696                for (end_offset, query_match) in query_matches {
14697                    let query_match = query_match.unwrap(); // can only fail due to I/O
14698                    let offset_range =
14699                        end_offset - query_match.end()..end_offset - query_match.start();
14700
14701                    if !select_prev_state.wordwise
14702                        || (!buffer.is_inside_word(offset_range.start, None)
14703                            && !buffer.is_inside_word(offset_range.end, None))
14704                    {
14705                        next_selected_range = Some(offset_range);
14706                        break;
14707                    }
14708                }
14709
14710                if let Some(next_selected_range) = next_selected_range {
14711                    self.select_match_ranges(
14712                        next_selected_range,
14713                        last_selection.reversed,
14714                        action.replace_newest,
14715                        Some(Autoscroll::newest()),
14716                        window,
14717                        cx,
14718                    );
14719                } else {
14720                    select_prev_state.done = true;
14721                }
14722            }
14723
14724            self.select_prev_state = Some(select_prev_state);
14725        } else {
14726            let mut only_carets = true;
14727            let mut same_text_selected = true;
14728            let mut selected_text = None;
14729
14730            let mut selections_iter = selections.iter().peekable();
14731            while let Some(selection) = selections_iter.next() {
14732                if selection.start != selection.end {
14733                    only_carets = false;
14734                }
14735
14736                if same_text_selected {
14737                    if selected_text.is_none() {
14738                        selected_text =
14739                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14740                    }
14741
14742                    if let Some(next_selection) = selections_iter.peek() {
14743                        if next_selection.range().len() == selection.range().len() {
14744                            let next_selected_text = buffer
14745                                .text_for_range(next_selection.range())
14746                                .collect::<String>();
14747                            if Some(next_selected_text) != selected_text {
14748                                same_text_selected = false;
14749                                selected_text = None;
14750                            }
14751                        } else {
14752                            same_text_selected = false;
14753                            selected_text = None;
14754                        }
14755                    }
14756                }
14757            }
14758
14759            if only_carets {
14760                for selection in &mut selections {
14761                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14762                    selection.start = word_range.start;
14763                    selection.end = word_range.end;
14764                    selection.goal = SelectionGoal::None;
14765                    selection.reversed = false;
14766                    self.select_match_ranges(
14767                        selection.start..selection.end,
14768                        selection.reversed,
14769                        action.replace_newest,
14770                        Some(Autoscroll::newest()),
14771                        window,
14772                        cx,
14773                    );
14774                }
14775                if selections.len() == 1 {
14776                    let selection = selections
14777                        .last()
14778                        .expect("ensured that there's only one selection");
14779                    let query = buffer
14780                        .text_for_range(selection.start..selection.end)
14781                        .collect::<String>();
14782                    let is_empty = query.is_empty();
14783                    let select_state = SelectNextState {
14784                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14785                        wordwise: true,
14786                        done: is_empty,
14787                    };
14788                    self.select_prev_state = Some(select_state);
14789                } else {
14790                    self.select_prev_state = None;
14791                }
14792            } else if let Some(selected_text) = selected_text {
14793                self.select_prev_state = Some(SelectNextState {
14794                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14795                    wordwise: false,
14796                    done: false,
14797                });
14798                self.select_previous(action, window, cx)?;
14799            }
14800        }
14801        Ok(())
14802    }
14803
14804    pub fn find_next_match(
14805        &mut self,
14806        _: &FindNextMatch,
14807        window: &mut Window,
14808        cx: &mut Context<Self>,
14809    ) -> Result<()> {
14810        let selections = self.selections.disjoint_anchors_arc();
14811        match selections.first() {
14812            Some(first) if selections.len() >= 2 => {
14813                self.change_selections(Default::default(), window, cx, |s| {
14814                    s.select_ranges([first.range()]);
14815                });
14816            }
14817            _ => self.select_next(
14818                &SelectNext {
14819                    replace_newest: true,
14820                },
14821                window,
14822                cx,
14823            )?,
14824        }
14825        Ok(())
14826    }
14827
14828    pub fn find_previous_match(
14829        &mut self,
14830        _: &FindPreviousMatch,
14831        window: &mut Window,
14832        cx: &mut Context<Self>,
14833    ) -> Result<()> {
14834        let selections = self.selections.disjoint_anchors_arc();
14835        match selections.last() {
14836            Some(last) if selections.len() >= 2 => {
14837                self.change_selections(Default::default(), window, cx, |s| {
14838                    s.select_ranges([last.range()]);
14839                });
14840            }
14841            _ => self.select_previous(
14842                &SelectPrevious {
14843                    replace_newest: true,
14844                },
14845                window,
14846                cx,
14847            )?,
14848        }
14849        Ok(())
14850    }
14851
14852    pub fn toggle_comments(
14853        &mut self,
14854        action: &ToggleComments,
14855        window: &mut Window,
14856        cx: &mut Context<Self>,
14857    ) {
14858        if self.read_only(cx) {
14859            return;
14860        }
14861        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14862        let text_layout_details = &self.text_layout_details(window);
14863        self.transact(window, cx, |this, window, cx| {
14864            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14865            let mut edits = Vec::new();
14866            let mut selection_edit_ranges = Vec::new();
14867            let mut last_toggled_row = None;
14868            let snapshot = this.buffer.read(cx).read(cx);
14869            let empty_str: Arc<str> = Arc::default();
14870            let mut suffixes_inserted = Vec::new();
14871            let ignore_indent = action.ignore_indent;
14872
14873            fn comment_prefix_range(
14874                snapshot: &MultiBufferSnapshot,
14875                row: MultiBufferRow,
14876                comment_prefix: &str,
14877                comment_prefix_whitespace: &str,
14878                ignore_indent: bool,
14879            ) -> Range<Point> {
14880                let indent_size = if ignore_indent {
14881                    0
14882                } else {
14883                    snapshot.indent_size_for_line(row).len
14884                };
14885
14886                let start = Point::new(row.0, indent_size);
14887
14888                let mut line_bytes = snapshot
14889                    .bytes_in_range(start..snapshot.max_point())
14890                    .flatten()
14891                    .copied();
14892
14893                // If this line currently begins with the line comment prefix, then record
14894                // the range containing the prefix.
14895                if line_bytes
14896                    .by_ref()
14897                    .take(comment_prefix.len())
14898                    .eq(comment_prefix.bytes())
14899                {
14900                    // Include any whitespace that matches the comment prefix.
14901                    let matching_whitespace_len = line_bytes
14902                        .zip(comment_prefix_whitespace.bytes())
14903                        .take_while(|(a, b)| a == b)
14904                        .count() as u32;
14905                    let end = Point::new(
14906                        start.row,
14907                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14908                    );
14909                    start..end
14910                } else {
14911                    start..start
14912                }
14913            }
14914
14915            fn comment_suffix_range(
14916                snapshot: &MultiBufferSnapshot,
14917                row: MultiBufferRow,
14918                comment_suffix: &str,
14919                comment_suffix_has_leading_space: bool,
14920            ) -> Range<Point> {
14921                let end = Point::new(row.0, snapshot.line_len(row));
14922                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14923
14924                let mut line_end_bytes = snapshot
14925                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14926                    .flatten()
14927                    .copied();
14928
14929                let leading_space_len = if suffix_start_column > 0
14930                    && line_end_bytes.next() == Some(b' ')
14931                    && comment_suffix_has_leading_space
14932                {
14933                    1
14934                } else {
14935                    0
14936                };
14937
14938                // If this line currently begins with the line comment prefix, then record
14939                // the range containing the prefix.
14940                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14941                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14942                    start..end
14943                } else {
14944                    end..end
14945                }
14946            }
14947
14948            // TODO: Handle selections that cross excerpts
14949            for selection in &mut selections {
14950                let start_column = snapshot
14951                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14952                    .len;
14953                let language = if let Some(language) =
14954                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14955                {
14956                    language
14957                } else {
14958                    continue;
14959                };
14960
14961                selection_edit_ranges.clear();
14962
14963                // If multiple selections contain a given row, avoid processing that
14964                // row more than once.
14965                let mut start_row = MultiBufferRow(selection.start.row);
14966                if last_toggled_row == Some(start_row) {
14967                    start_row = start_row.next_row();
14968                }
14969                let end_row =
14970                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14971                        MultiBufferRow(selection.end.row - 1)
14972                    } else {
14973                        MultiBufferRow(selection.end.row)
14974                    };
14975                last_toggled_row = Some(end_row);
14976
14977                if start_row > end_row {
14978                    continue;
14979                }
14980
14981                // If the language has line comments, toggle those.
14982                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14983
14984                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14985                if ignore_indent {
14986                    full_comment_prefixes = full_comment_prefixes
14987                        .into_iter()
14988                        .map(|s| Arc::from(s.trim_end()))
14989                        .collect();
14990                }
14991
14992                if !full_comment_prefixes.is_empty() {
14993                    let first_prefix = full_comment_prefixes
14994                        .first()
14995                        .expect("prefixes is non-empty");
14996                    let prefix_trimmed_lengths = full_comment_prefixes
14997                        .iter()
14998                        .map(|p| p.trim_end_matches(' ').len())
14999                        .collect::<SmallVec<[usize; 4]>>();
15000
15001                    let mut all_selection_lines_are_comments = true;
15002
15003                    for row in start_row.0..=end_row.0 {
15004                        let row = MultiBufferRow(row);
15005                        if start_row < end_row && snapshot.is_line_blank(row) {
15006                            continue;
15007                        }
15008
15009                        let prefix_range = full_comment_prefixes
15010                            .iter()
15011                            .zip(prefix_trimmed_lengths.iter().copied())
15012                            .map(|(prefix, trimmed_prefix_len)| {
15013                                comment_prefix_range(
15014                                    snapshot.deref(),
15015                                    row,
15016                                    &prefix[..trimmed_prefix_len],
15017                                    &prefix[trimmed_prefix_len..],
15018                                    ignore_indent,
15019                                )
15020                            })
15021                            .max_by_key(|range| range.end.column - range.start.column)
15022                            .expect("prefixes is non-empty");
15023
15024                        if prefix_range.is_empty() {
15025                            all_selection_lines_are_comments = false;
15026                        }
15027
15028                        selection_edit_ranges.push(prefix_range);
15029                    }
15030
15031                    if all_selection_lines_are_comments {
15032                        edits.extend(
15033                            selection_edit_ranges
15034                                .iter()
15035                                .cloned()
15036                                .map(|range| (range, empty_str.clone())),
15037                        );
15038                    } else {
15039                        let min_column = selection_edit_ranges
15040                            .iter()
15041                            .map(|range| range.start.column)
15042                            .min()
15043                            .unwrap_or(0);
15044                        edits.extend(selection_edit_ranges.iter().map(|range| {
15045                            let position = Point::new(range.start.row, min_column);
15046                            (position..position, first_prefix.clone())
15047                        }));
15048                    }
15049                } else if let Some(BlockCommentConfig {
15050                    start: full_comment_prefix,
15051                    end: comment_suffix,
15052                    ..
15053                }) = language.block_comment()
15054                {
15055                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15056                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15057                    let prefix_range = comment_prefix_range(
15058                        snapshot.deref(),
15059                        start_row,
15060                        comment_prefix,
15061                        comment_prefix_whitespace,
15062                        ignore_indent,
15063                    );
15064                    let suffix_range = comment_suffix_range(
15065                        snapshot.deref(),
15066                        end_row,
15067                        comment_suffix.trim_start_matches(' '),
15068                        comment_suffix.starts_with(' '),
15069                    );
15070
15071                    if prefix_range.is_empty() || suffix_range.is_empty() {
15072                        edits.push((
15073                            prefix_range.start..prefix_range.start,
15074                            full_comment_prefix.clone(),
15075                        ));
15076                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15077                        suffixes_inserted.push((end_row, comment_suffix.len()));
15078                    } else {
15079                        edits.push((prefix_range, empty_str.clone()));
15080                        edits.push((suffix_range, empty_str.clone()));
15081                    }
15082                } else {
15083                    continue;
15084                }
15085            }
15086
15087            drop(snapshot);
15088            this.buffer.update(cx, |buffer, cx| {
15089                buffer.edit(edits, None, cx);
15090            });
15091
15092            // Adjust selections so that they end before any comment suffixes that
15093            // were inserted.
15094            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15095            let mut selections = this.selections.all::<Point>(cx);
15096            let snapshot = this.buffer.read(cx).read(cx);
15097            for selection in &mut selections {
15098                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15099                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15100                        Ordering::Less => {
15101                            suffixes_inserted.next();
15102                            continue;
15103                        }
15104                        Ordering::Greater => break,
15105                        Ordering::Equal => {
15106                            if selection.end.column == snapshot.line_len(row) {
15107                                if selection.is_empty() {
15108                                    selection.start.column -= suffix_len as u32;
15109                                }
15110                                selection.end.column -= suffix_len as u32;
15111                            }
15112                            break;
15113                        }
15114                    }
15115                }
15116            }
15117
15118            drop(snapshot);
15119            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15120
15121            let selections = this.selections.all::<Point>(cx);
15122            let selections_on_single_row = selections.windows(2).all(|selections| {
15123                selections[0].start.row == selections[1].start.row
15124                    && selections[0].end.row == selections[1].end.row
15125                    && selections[0].start.row == selections[0].end.row
15126            });
15127            let selections_selecting = selections
15128                .iter()
15129                .any(|selection| selection.start != selection.end);
15130            let advance_downwards = action.advance_downwards
15131                && selections_on_single_row
15132                && !selections_selecting
15133                && !matches!(this.mode, EditorMode::SingleLine);
15134
15135            if advance_downwards {
15136                let snapshot = this.buffer.read(cx).snapshot(cx);
15137
15138                this.change_selections(Default::default(), window, cx, |s| {
15139                    s.move_cursors_with(|display_snapshot, display_point, _| {
15140                        let mut point = display_point.to_point(display_snapshot);
15141                        point.row += 1;
15142                        point = snapshot.clip_point(point, Bias::Left);
15143                        let display_point = point.to_display_point(display_snapshot);
15144                        let goal = SelectionGoal::HorizontalPosition(
15145                            display_snapshot
15146                                .x_for_display_point(display_point, text_layout_details)
15147                                .into(),
15148                        );
15149                        (display_point, goal)
15150                    })
15151                });
15152            }
15153        });
15154    }
15155
15156    pub fn select_enclosing_symbol(
15157        &mut self,
15158        _: &SelectEnclosingSymbol,
15159        window: &mut Window,
15160        cx: &mut Context<Self>,
15161    ) {
15162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15163
15164        let buffer = self.buffer.read(cx).snapshot(cx);
15165        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15166
15167        fn update_selection(
15168            selection: &Selection<usize>,
15169            buffer_snap: &MultiBufferSnapshot,
15170        ) -> Option<Selection<usize>> {
15171            let cursor = selection.head();
15172            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15173            for symbol in symbols.iter().rev() {
15174                let start = symbol.range.start.to_offset(buffer_snap);
15175                let end = symbol.range.end.to_offset(buffer_snap);
15176                let new_range = start..end;
15177                if start < selection.start || end > selection.end {
15178                    return Some(Selection {
15179                        id: selection.id,
15180                        start: new_range.start,
15181                        end: new_range.end,
15182                        goal: SelectionGoal::None,
15183                        reversed: selection.reversed,
15184                    });
15185                }
15186            }
15187            None
15188        }
15189
15190        let mut selected_larger_symbol = false;
15191        let new_selections = old_selections
15192            .iter()
15193            .map(|selection| match update_selection(selection, &buffer) {
15194                Some(new_selection) => {
15195                    if new_selection.range() != selection.range() {
15196                        selected_larger_symbol = true;
15197                    }
15198                    new_selection
15199                }
15200                None => selection.clone(),
15201            })
15202            .collect::<Vec<_>>();
15203
15204        if selected_larger_symbol {
15205            self.change_selections(Default::default(), window, cx, |s| {
15206                s.select(new_selections);
15207            });
15208        }
15209    }
15210
15211    pub fn select_larger_syntax_node(
15212        &mut self,
15213        _: &SelectLargerSyntaxNode,
15214        window: &mut Window,
15215        cx: &mut Context<Self>,
15216    ) {
15217        let Some(visible_row_count) = self.visible_row_count() else {
15218            return;
15219        };
15220        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15221        if old_selections.is_empty() {
15222            return;
15223        }
15224
15225        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15226
15227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15228        let buffer = self.buffer.read(cx).snapshot(cx);
15229
15230        let mut selected_larger_node = false;
15231        let mut new_selections = old_selections
15232            .iter()
15233            .map(|selection| {
15234                let old_range = selection.start..selection.end;
15235
15236                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15237                    // manually select word at selection
15238                    if ["string_content", "inline"].contains(&node.kind()) {
15239                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15240                        // ignore if word is already selected
15241                        if !word_range.is_empty() && old_range != word_range {
15242                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15243                            // only select word if start and end point belongs to same word
15244                            if word_range == last_word_range {
15245                                selected_larger_node = true;
15246                                return Selection {
15247                                    id: selection.id,
15248                                    start: word_range.start,
15249                                    end: word_range.end,
15250                                    goal: SelectionGoal::None,
15251                                    reversed: selection.reversed,
15252                                };
15253                            }
15254                        }
15255                    }
15256                }
15257
15258                let mut new_range = old_range.clone();
15259                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15260                    new_range = range;
15261                    if !node.is_named() {
15262                        continue;
15263                    }
15264                    if !display_map.intersects_fold(new_range.start)
15265                        && !display_map.intersects_fold(new_range.end)
15266                    {
15267                        break;
15268                    }
15269                }
15270
15271                selected_larger_node |= new_range != old_range;
15272                Selection {
15273                    id: selection.id,
15274                    start: new_range.start,
15275                    end: new_range.end,
15276                    goal: SelectionGoal::None,
15277                    reversed: selection.reversed,
15278                }
15279            })
15280            .collect::<Vec<_>>();
15281
15282        if !selected_larger_node {
15283            return; // don't put this call in the history
15284        }
15285
15286        // scroll based on transformation done to the last selection created by the user
15287        let (last_old, last_new) = old_selections
15288            .last()
15289            .zip(new_selections.last().cloned())
15290            .expect("old_selections isn't empty");
15291
15292        // revert selection
15293        let is_selection_reversed = {
15294            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15295            new_selections.last_mut().expect("checked above").reversed =
15296                should_newest_selection_be_reversed;
15297            should_newest_selection_be_reversed
15298        };
15299
15300        if selected_larger_node {
15301            self.select_syntax_node_history.disable_clearing = true;
15302            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15303                s.select(new_selections.clone());
15304            });
15305            self.select_syntax_node_history.disable_clearing = false;
15306        }
15307
15308        let start_row = last_new.start.to_display_point(&display_map).row().0;
15309        let end_row = last_new.end.to_display_point(&display_map).row().0;
15310        let selection_height = end_row - start_row + 1;
15311        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15312
15313        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15314        let scroll_behavior = if fits_on_the_screen {
15315            self.request_autoscroll(Autoscroll::fit(), cx);
15316            SelectSyntaxNodeScrollBehavior::FitSelection
15317        } else if is_selection_reversed {
15318            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15319            SelectSyntaxNodeScrollBehavior::CursorTop
15320        } else {
15321            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15322            SelectSyntaxNodeScrollBehavior::CursorBottom
15323        };
15324
15325        self.select_syntax_node_history.push((
15326            old_selections,
15327            scroll_behavior,
15328            is_selection_reversed,
15329        ));
15330    }
15331
15332    pub fn select_smaller_syntax_node(
15333        &mut self,
15334        _: &SelectSmallerSyntaxNode,
15335        window: &mut Window,
15336        cx: &mut Context<Self>,
15337    ) {
15338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15339
15340        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15341            self.select_syntax_node_history.pop()
15342        {
15343            if let Some(selection) = selections.last_mut() {
15344                selection.reversed = is_selection_reversed;
15345            }
15346
15347            self.select_syntax_node_history.disable_clearing = true;
15348            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15349                s.select(selections.to_vec());
15350            });
15351            self.select_syntax_node_history.disable_clearing = false;
15352
15353            match scroll_behavior {
15354                SelectSyntaxNodeScrollBehavior::CursorTop => {
15355                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15356                }
15357                SelectSyntaxNodeScrollBehavior::FitSelection => {
15358                    self.request_autoscroll(Autoscroll::fit(), cx);
15359                }
15360                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15361                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15362                }
15363            }
15364        }
15365    }
15366
15367    pub fn unwrap_syntax_node(
15368        &mut self,
15369        _: &UnwrapSyntaxNode,
15370        window: &mut Window,
15371        cx: &mut Context<Self>,
15372    ) {
15373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15374
15375        let buffer = self.buffer.read(cx).snapshot(cx);
15376        let selections = self
15377            .selections
15378            .all::<usize>(cx)
15379            .into_iter()
15380            // subtracting the offset requires sorting
15381            .sorted_by_key(|i| i.start);
15382
15383        let full_edits = selections
15384            .into_iter()
15385            .filter_map(|selection| {
15386                let child = if selection.is_empty()
15387                    && let Some((_, ancestor_range)) =
15388                        buffer.syntax_ancestor(selection.start..selection.end)
15389                {
15390                    ancestor_range
15391                } else {
15392                    selection.range()
15393                };
15394
15395                let mut parent = child.clone();
15396                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15397                    parent = ancestor_range;
15398                    if parent.start < child.start || parent.end > child.end {
15399                        break;
15400                    }
15401                }
15402
15403                if parent == child {
15404                    return None;
15405                }
15406                let text = buffer.text_for_range(child).collect::<String>();
15407                Some((selection.id, parent, text))
15408            })
15409            .collect::<Vec<_>>();
15410        if full_edits.is_empty() {
15411            return;
15412        }
15413
15414        self.transact(window, cx, |this, window, cx| {
15415            this.buffer.update(cx, |buffer, cx| {
15416                buffer.edit(
15417                    full_edits
15418                        .iter()
15419                        .map(|(_, p, t)| (p.clone(), t.clone()))
15420                        .collect::<Vec<_>>(),
15421                    None,
15422                    cx,
15423                );
15424            });
15425            this.change_selections(Default::default(), window, cx, |s| {
15426                let mut offset = 0;
15427                let mut selections = vec![];
15428                for (id, parent, text) in full_edits {
15429                    let start = parent.start - offset;
15430                    offset += parent.len() - text.len();
15431                    selections.push(Selection {
15432                        id,
15433                        start,
15434                        end: start + text.len(),
15435                        reversed: false,
15436                        goal: Default::default(),
15437                    });
15438                }
15439                s.select(selections);
15440            });
15441        });
15442    }
15443
15444    pub fn select_next_syntax_node(
15445        &mut self,
15446        _: &SelectNextSyntaxNode,
15447        window: &mut Window,
15448        cx: &mut Context<Self>,
15449    ) {
15450        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15451        if old_selections.is_empty() {
15452            return;
15453        }
15454
15455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15456
15457        let buffer = self.buffer.read(cx).snapshot(cx);
15458        let mut selected_sibling = false;
15459
15460        let new_selections = old_selections
15461            .iter()
15462            .map(|selection| {
15463                let old_range = selection.start..selection.end;
15464
15465                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15466                    let new_range = node.byte_range();
15467                    selected_sibling = true;
15468                    Selection {
15469                        id: selection.id,
15470                        start: new_range.start,
15471                        end: new_range.end,
15472                        goal: SelectionGoal::None,
15473                        reversed: selection.reversed,
15474                    }
15475                } else {
15476                    selection.clone()
15477                }
15478            })
15479            .collect::<Vec<_>>();
15480
15481        if selected_sibling {
15482            self.change_selections(
15483                SelectionEffects::scroll(Autoscroll::fit()),
15484                window,
15485                cx,
15486                |s| {
15487                    s.select(new_selections);
15488                },
15489            );
15490        }
15491    }
15492
15493    pub fn select_prev_syntax_node(
15494        &mut self,
15495        _: &SelectPreviousSyntaxNode,
15496        window: &mut Window,
15497        cx: &mut Context<Self>,
15498    ) {
15499        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15500        if old_selections.is_empty() {
15501            return;
15502        }
15503
15504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15505
15506        let buffer = self.buffer.read(cx).snapshot(cx);
15507        let mut selected_sibling = false;
15508
15509        let new_selections = old_selections
15510            .iter()
15511            .map(|selection| {
15512                let old_range = selection.start..selection.end;
15513
15514                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15515                    let new_range = node.byte_range();
15516                    selected_sibling = true;
15517                    Selection {
15518                        id: selection.id,
15519                        start: new_range.start,
15520                        end: new_range.end,
15521                        goal: SelectionGoal::None,
15522                        reversed: selection.reversed,
15523                    }
15524                } else {
15525                    selection.clone()
15526                }
15527            })
15528            .collect::<Vec<_>>();
15529
15530        if selected_sibling {
15531            self.change_selections(
15532                SelectionEffects::scroll(Autoscroll::fit()),
15533                window,
15534                cx,
15535                |s| {
15536                    s.select(new_selections);
15537                },
15538            );
15539        }
15540    }
15541
15542    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15543        if !EditorSettings::get_global(cx).gutter.runnables {
15544            self.clear_tasks();
15545            return Task::ready(());
15546        }
15547        let project = self.project().map(Entity::downgrade);
15548        let task_sources = self.lsp_task_sources(cx);
15549        let multi_buffer = self.buffer.downgrade();
15550        cx.spawn_in(window, async move |editor, cx| {
15551            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15552            let Some(project) = project.and_then(|p| p.upgrade()) else {
15553                return;
15554            };
15555            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15556                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15557            }) else {
15558                return;
15559            };
15560
15561            let hide_runnables = project
15562                .update(cx, |project, _| project.is_via_collab())
15563                .unwrap_or(true);
15564            if hide_runnables {
15565                return;
15566            }
15567            let new_rows =
15568                cx.background_spawn({
15569                    let snapshot = display_snapshot.clone();
15570                    async move {
15571                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15572                    }
15573                })
15574                    .await;
15575            let Ok(lsp_tasks) =
15576                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15577            else {
15578                return;
15579            };
15580            let lsp_tasks = lsp_tasks.await;
15581
15582            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15583                lsp_tasks
15584                    .into_iter()
15585                    .flat_map(|(kind, tasks)| {
15586                        tasks.into_iter().filter_map(move |(location, task)| {
15587                            Some((kind.clone(), location?, task))
15588                        })
15589                    })
15590                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15591                        let buffer = location.target.buffer;
15592                        let buffer_snapshot = buffer.read(cx).snapshot();
15593                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15594                            |(excerpt_id, snapshot, _)| {
15595                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15596                                    display_snapshot
15597                                        .buffer_snapshot()
15598                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15599                                } else {
15600                                    None
15601                                }
15602                            },
15603                        );
15604                        if let Some(offset) = offset {
15605                            let task_buffer_range =
15606                                location.target.range.to_point(&buffer_snapshot);
15607                            let context_buffer_range =
15608                                task_buffer_range.to_offset(&buffer_snapshot);
15609                            let context_range = BufferOffset(context_buffer_range.start)
15610                                ..BufferOffset(context_buffer_range.end);
15611
15612                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15613                                .or_insert_with(|| RunnableTasks {
15614                                    templates: Vec::new(),
15615                                    offset,
15616                                    column: task_buffer_range.start.column,
15617                                    extra_variables: HashMap::default(),
15618                                    context_range,
15619                                })
15620                                .templates
15621                                .push((kind, task.original_task().clone()));
15622                        }
15623
15624                        acc
15625                    })
15626            }) else {
15627                return;
15628            };
15629
15630            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15631                buffer.language_settings(cx).tasks.prefer_lsp
15632            }) else {
15633                return;
15634            };
15635
15636            let rows = Self::runnable_rows(
15637                project,
15638                display_snapshot,
15639                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15640                new_rows,
15641                cx.clone(),
15642            )
15643            .await;
15644            editor
15645                .update(cx, |editor, _| {
15646                    editor.clear_tasks();
15647                    for (key, mut value) in rows {
15648                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15649                            value.templates.extend(lsp_tasks.templates);
15650                        }
15651
15652                        editor.insert_tasks(key, value);
15653                    }
15654                    for (key, value) in lsp_tasks_by_rows {
15655                        editor.insert_tasks(key, value);
15656                    }
15657                })
15658                .ok();
15659        })
15660    }
15661    fn fetch_runnable_ranges(
15662        snapshot: &DisplaySnapshot,
15663        range: Range<Anchor>,
15664    ) -> Vec<language::RunnableRange> {
15665        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15666    }
15667
15668    fn runnable_rows(
15669        project: Entity<Project>,
15670        snapshot: DisplaySnapshot,
15671        prefer_lsp: bool,
15672        runnable_ranges: Vec<RunnableRange>,
15673        cx: AsyncWindowContext,
15674    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15675        cx.spawn(async move |cx| {
15676            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15677            for mut runnable in runnable_ranges {
15678                let Some(tasks) = cx
15679                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15680                    .ok()
15681                else {
15682                    continue;
15683                };
15684                let mut tasks = tasks.await;
15685
15686                if prefer_lsp {
15687                    tasks.retain(|(task_kind, _)| {
15688                        !matches!(task_kind, TaskSourceKind::Language { .. })
15689                    });
15690                }
15691                if tasks.is_empty() {
15692                    continue;
15693                }
15694
15695                let point = runnable
15696                    .run_range
15697                    .start
15698                    .to_point(&snapshot.buffer_snapshot());
15699                let Some(row) = snapshot
15700                    .buffer_snapshot()
15701                    .buffer_line_for_row(MultiBufferRow(point.row))
15702                    .map(|(_, range)| range.start.row)
15703                else {
15704                    continue;
15705                };
15706
15707                let context_range =
15708                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15709                runnable_rows.push((
15710                    (runnable.buffer_id, row),
15711                    RunnableTasks {
15712                        templates: tasks,
15713                        offset: snapshot
15714                            .buffer_snapshot()
15715                            .anchor_before(runnable.run_range.start),
15716                        context_range,
15717                        column: point.column,
15718                        extra_variables: runnable.extra_captures,
15719                    },
15720                ));
15721            }
15722            runnable_rows
15723        })
15724    }
15725
15726    fn templates_with_tags(
15727        project: &Entity<Project>,
15728        runnable: &mut Runnable,
15729        cx: &mut App,
15730    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15731        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15732            let (worktree_id, file) = project
15733                .buffer_for_id(runnable.buffer, cx)
15734                .and_then(|buffer| buffer.read(cx).file())
15735                .map(|file| (file.worktree_id(cx), file.clone()))
15736                .unzip();
15737
15738            (
15739                project.task_store().read(cx).task_inventory().cloned(),
15740                worktree_id,
15741                file,
15742            )
15743        });
15744
15745        let tags = mem::take(&mut runnable.tags);
15746        let language = runnable.language.clone();
15747        cx.spawn(async move |cx| {
15748            let mut templates_with_tags = Vec::new();
15749            if let Some(inventory) = inventory {
15750                for RunnableTag(tag) in tags {
15751                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15752                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15753                    }) else {
15754                        return templates_with_tags;
15755                    };
15756                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15757                        move |(_, template)| {
15758                            template.tags.iter().any(|source_tag| source_tag == &tag)
15759                        },
15760                    ));
15761                }
15762            }
15763            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15764
15765            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15766                // Strongest source wins; if we have worktree tag binding, prefer that to
15767                // global and language bindings;
15768                // if we have a global binding, prefer that to language binding.
15769                let first_mismatch = templates_with_tags
15770                    .iter()
15771                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15772                if let Some(index) = first_mismatch {
15773                    templates_with_tags.truncate(index);
15774                }
15775            }
15776
15777            templates_with_tags
15778        })
15779    }
15780
15781    pub fn move_to_enclosing_bracket(
15782        &mut self,
15783        _: &MoveToEnclosingBracket,
15784        window: &mut Window,
15785        cx: &mut Context<Self>,
15786    ) {
15787        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15788        self.change_selections(Default::default(), window, cx, |s| {
15789            s.move_offsets_with(|snapshot, selection| {
15790                let Some(enclosing_bracket_ranges) =
15791                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15792                else {
15793                    return;
15794                };
15795
15796                let mut best_length = usize::MAX;
15797                let mut best_inside = false;
15798                let mut best_in_bracket_range = false;
15799                let mut best_destination = None;
15800                for (open, close) in enclosing_bracket_ranges {
15801                    let close = close.to_inclusive();
15802                    let length = close.end() - open.start;
15803                    let inside = selection.start >= open.end && selection.end <= *close.start();
15804                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15805                        || close.contains(&selection.head());
15806
15807                    // If best is next to a bracket and current isn't, skip
15808                    if !in_bracket_range && best_in_bracket_range {
15809                        continue;
15810                    }
15811
15812                    // Prefer smaller lengths unless best is inside and current isn't
15813                    if length > best_length && (best_inside || !inside) {
15814                        continue;
15815                    }
15816
15817                    best_length = length;
15818                    best_inside = inside;
15819                    best_in_bracket_range = in_bracket_range;
15820                    best_destination = Some(
15821                        if close.contains(&selection.start) && close.contains(&selection.end) {
15822                            if inside { open.end } else { open.start }
15823                        } else if inside {
15824                            *close.start()
15825                        } else {
15826                            *close.end()
15827                        },
15828                    );
15829                }
15830
15831                if let Some(destination) = best_destination {
15832                    selection.collapse_to(destination, SelectionGoal::None);
15833                }
15834            })
15835        });
15836    }
15837
15838    pub fn undo_selection(
15839        &mut self,
15840        _: &UndoSelection,
15841        window: &mut Window,
15842        cx: &mut Context<Self>,
15843    ) {
15844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15845        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15846            self.selection_history.mode = SelectionHistoryMode::Undoing;
15847            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15848                this.end_selection(window, cx);
15849                this.change_selections(
15850                    SelectionEffects::scroll(Autoscroll::newest()),
15851                    window,
15852                    cx,
15853                    |s| s.select_anchors(entry.selections.to_vec()),
15854                );
15855            });
15856            self.selection_history.mode = SelectionHistoryMode::Normal;
15857
15858            self.select_next_state = entry.select_next_state;
15859            self.select_prev_state = entry.select_prev_state;
15860            self.add_selections_state = entry.add_selections_state;
15861        }
15862    }
15863
15864    pub fn redo_selection(
15865        &mut self,
15866        _: &RedoSelection,
15867        window: &mut Window,
15868        cx: &mut Context<Self>,
15869    ) {
15870        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15871        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15872            self.selection_history.mode = SelectionHistoryMode::Redoing;
15873            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15874                this.end_selection(window, cx);
15875                this.change_selections(
15876                    SelectionEffects::scroll(Autoscroll::newest()),
15877                    window,
15878                    cx,
15879                    |s| s.select_anchors(entry.selections.to_vec()),
15880                );
15881            });
15882            self.selection_history.mode = SelectionHistoryMode::Normal;
15883
15884            self.select_next_state = entry.select_next_state;
15885            self.select_prev_state = entry.select_prev_state;
15886            self.add_selections_state = entry.add_selections_state;
15887        }
15888    }
15889
15890    pub fn expand_excerpts(
15891        &mut self,
15892        action: &ExpandExcerpts,
15893        _: &mut Window,
15894        cx: &mut Context<Self>,
15895    ) {
15896        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15897    }
15898
15899    pub fn expand_excerpts_down(
15900        &mut self,
15901        action: &ExpandExcerptsDown,
15902        _: &mut Window,
15903        cx: &mut Context<Self>,
15904    ) {
15905        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15906    }
15907
15908    pub fn expand_excerpts_up(
15909        &mut self,
15910        action: &ExpandExcerptsUp,
15911        _: &mut Window,
15912        cx: &mut Context<Self>,
15913    ) {
15914        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15915    }
15916
15917    pub fn expand_excerpts_for_direction(
15918        &mut self,
15919        lines: u32,
15920        direction: ExpandExcerptDirection,
15921
15922        cx: &mut Context<Self>,
15923    ) {
15924        let selections = self.selections.disjoint_anchors_arc();
15925
15926        let lines = if lines == 0 {
15927            EditorSettings::get_global(cx).expand_excerpt_lines
15928        } else {
15929            lines
15930        };
15931
15932        self.buffer.update(cx, |buffer, cx| {
15933            let snapshot = buffer.snapshot(cx);
15934            let mut excerpt_ids = selections
15935                .iter()
15936                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15937                .collect::<Vec<_>>();
15938            excerpt_ids.sort();
15939            excerpt_ids.dedup();
15940            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15941        })
15942    }
15943
15944    pub fn expand_excerpt(
15945        &mut self,
15946        excerpt: ExcerptId,
15947        direction: ExpandExcerptDirection,
15948        window: &mut Window,
15949        cx: &mut Context<Self>,
15950    ) {
15951        let current_scroll_position = self.scroll_position(cx);
15952        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15953        let mut should_scroll_up = false;
15954
15955        if direction == ExpandExcerptDirection::Down {
15956            let multi_buffer = self.buffer.read(cx);
15957            let snapshot = multi_buffer.snapshot(cx);
15958            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15959                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15960                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15961            {
15962                let buffer_snapshot = buffer.read(cx).snapshot();
15963                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15964                let last_row = buffer_snapshot.max_point().row;
15965                let lines_below = last_row.saturating_sub(excerpt_end_row);
15966                should_scroll_up = lines_below >= lines_to_expand;
15967            }
15968        }
15969
15970        self.buffer.update(cx, |buffer, cx| {
15971            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15972        });
15973
15974        if should_scroll_up {
15975            let new_scroll_position =
15976                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15977            self.set_scroll_position(new_scroll_position, window, cx);
15978        }
15979    }
15980
15981    pub fn go_to_singleton_buffer_point(
15982        &mut self,
15983        point: Point,
15984        window: &mut Window,
15985        cx: &mut Context<Self>,
15986    ) {
15987        self.go_to_singleton_buffer_range(point..point, window, cx);
15988    }
15989
15990    pub fn go_to_singleton_buffer_range(
15991        &mut self,
15992        range: Range<Point>,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) {
15996        let multibuffer = self.buffer().read(cx);
15997        let Some(buffer) = multibuffer.as_singleton() else {
15998            return;
15999        };
16000        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16001            return;
16002        };
16003        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16004            return;
16005        };
16006        self.change_selections(
16007            SelectionEffects::default().nav_history(true),
16008            window,
16009            cx,
16010            |s| s.select_anchor_ranges([start..end]),
16011        );
16012    }
16013
16014    pub fn go_to_diagnostic(
16015        &mut self,
16016        action: &GoToDiagnostic,
16017        window: &mut Window,
16018        cx: &mut Context<Self>,
16019    ) {
16020        if !self.diagnostics_enabled() {
16021            return;
16022        }
16023        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16024        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16025    }
16026
16027    pub fn go_to_prev_diagnostic(
16028        &mut self,
16029        action: &GoToPreviousDiagnostic,
16030        window: &mut Window,
16031        cx: &mut Context<Self>,
16032    ) {
16033        if !self.diagnostics_enabled() {
16034            return;
16035        }
16036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16037        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16038    }
16039
16040    pub fn go_to_diagnostic_impl(
16041        &mut self,
16042        direction: Direction,
16043        severity: GoToDiagnosticSeverityFilter,
16044        window: &mut Window,
16045        cx: &mut Context<Self>,
16046    ) {
16047        let buffer = self.buffer.read(cx).snapshot(cx);
16048        let selection = self.selections.newest::<usize>(cx);
16049
16050        let mut active_group_id = None;
16051        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16052            && active_group.active_range.start.to_offset(&buffer) == selection.start
16053        {
16054            active_group_id = Some(active_group.group_id);
16055        }
16056
16057        fn filtered<'a>(
16058            snapshot: EditorSnapshot,
16059            severity: GoToDiagnosticSeverityFilter,
16060            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16061        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16062            diagnostics
16063                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16064                .filter(|entry| entry.range.start != entry.range.end)
16065                .filter(|entry| !entry.diagnostic.is_unnecessary)
16066                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16067        }
16068
16069        let snapshot = self.snapshot(window, cx);
16070        let before = filtered(
16071            snapshot.clone(),
16072            severity,
16073            buffer
16074                .diagnostics_in_range(0..selection.start)
16075                .filter(|entry| entry.range.start <= selection.start),
16076        );
16077        let after = filtered(
16078            snapshot,
16079            severity,
16080            buffer
16081                .diagnostics_in_range(selection.start..buffer.len())
16082                .filter(|entry| entry.range.start >= selection.start),
16083        );
16084
16085        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16086        if direction == Direction::Prev {
16087            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16088            {
16089                for diagnostic in prev_diagnostics.into_iter().rev() {
16090                    if diagnostic.range.start != selection.start
16091                        || active_group_id
16092                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16093                    {
16094                        found = Some(diagnostic);
16095                        break 'outer;
16096                    }
16097                }
16098            }
16099        } else {
16100            for diagnostic in after.chain(before) {
16101                if diagnostic.range.start != selection.start
16102                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16103                {
16104                    found = Some(diagnostic);
16105                    break;
16106                }
16107            }
16108        }
16109        let Some(next_diagnostic) = found else {
16110            return;
16111        };
16112
16113        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16114        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16115            return;
16116        };
16117        self.change_selections(Default::default(), window, cx, |s| {
16118            s.select_ranges(vec![
16119                next_diagnostic.range.start..next_diagnostic.range.start,
16120            ])
16121        });
16122        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16123        self.refresh_edit_prediction(false, true, window, cx);
16124    }
16125
16126    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16128        let snapshot = self.snapshot(window, cx);
16129        let selection = self.selections.newest::<Point>(cx);
16130        self.go_to_hunk_before_or_after_position(
16131            &snapshot,
16132            selection.head(),
16133            Direction::Next,
16134            window,
16135            cx,
16136        );
16137    }
16138
16139    pub fn go_to_hunk_before_or_after_position(
16140        &mut self,
16141        snapshot: &EditorSnapshot,
16142        position: Point,
16143        direction: Direction,
16144        window: &mut Window,
16145        cx: &mut Context<Editor>,
16146    ) {
16147        let row = if direction == Direction::Next {
16148            self.hunk_after_position(snapshot, position)
16149                .map(|hunk| hunk.row_range.start)
16150        } else {
16151            self.hunk_before_position(snapshot, position)
16152        };
16153
16154        if let Some(row) = row {
16155            let destination = Point::new(row.0, 0);
16156            let autoscroll = Autoscroll::center();
16157
16158            self.unfold_ranges(&[destination..destination], false, false, cx);
16159            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16160                s.select_ranges([destination..destination]);
16161            });
16162        }
16163    }
16164
16165    fn hunk_after_position(
16166        &mut self,
16167        snapshot: &EditorSnapshot,
16168        position: Point,
16169    ) -> Option<MultiBufferDiffHunk> {
16170        snapshot
16171            .buffer_snapshot()
16172            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16173            .find(|hunk| hunk.row_range.start.0 > position.row)
16174            .or_else(|| {
16175                snapshot
16176                    .buffer_snapshot()
16177                    .diff_hunks_in_range(Point::zero()..position)
16178                    .find(|hunk| hunk.row_range.end.0 < position.row)
16179            })
16180    }
16181
16182    fn go_to_prev_hunk(
16183        &mut self,
16184        _: &GoToPreviousHunk,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) {
16188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16189        let snapshot = self.snapshot(window, cx);
16190        let selection = self.selections.newest::<Point>(cx);
16191        self.go_to_hunk_before_or_after_position(
16192            &snapshot,
16193            selection.head(),
16194            Direction::Prev,
16195            window,
16196            cx,
16197        );
16198    }
16199
16200    fn hunk_before_position(
16201        &mut self,
16202        snapshot: &EditorSnapshot,
16203        position: Point,
16204    ) -> Option<MultiBufferRow> {
16205        snapshot
16206            .buffer_snapshot()
16207            .diff_hunk_before(position)
16208            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16209    }
16210
16211    fn go_to_next_change(
16212        &mut self,
16213        _: &GoToNextChange,
16214        window: &mut Window,
16215        cx: &mut Context<Self>,
16216    ) {
16217        if let Some(selections) = self
16218            .change_list
16219            .next_change(1, Direction::Next)
16220            .map(|s| s.to_vec())
16221        {
16222            self.change_selections(Default::default(), window, cx, |s| {
16223                let map = s.display_map();
16224                s.select_display_ranges(selections.iter().map(|a| {
16225                    let point = a.to_display_point(&map);
16226                    point..point
16227                }))
16228            })
16229        }
16230    }
16231
16232    fn go_to_previous_change(
16233        &mut self,
16234        _: &GoToPreviousChange,
16235        window: &mut Window,
16236        cx: &mut Context<Self>,
16237    ) {
16238        if let Some(selections) = self
16239            .change_list
16240            .next_change(1, Direction::Prev)
16241            .map(|s| s.to_vec())
16242        {
16243            self.change_selections(Default::default(), window, cx, |s| {
16244                let map = s.display_map();
16245                s.select_display_ranges(selections.iter().map(|a| {
16246                    let point = a.to_display_point(&map);
16247                    point..point
16248                }))
16249            })
16250        }
16251    }
16252
16253    pub fn go_to_next_document_highlight(
16254        &mut self,
16255        _: &GoToNextDocumentHighlight,
16256        window: &mut Window,
16257        cx: &mut Context<Self>,
16258    ) {
16259        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16260    }
16261
16262    pub fn go_to_prev_document_highlight(
16263        &mut self,
16264        _: &GoToPreviousDocumentHighlight,
16265        window: &mut Window,
16266        cx: &mut Context<Self>,
16267    ) {
16268        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16269    }
16270
16271    pub fn go_to_document_highlight_before_or_after_position(
16272        &mut self,
16273        direction: Direction,
16274        window: &mut Window,
16275        cx: &mut Context<Editor>,
16276    ) {
16277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16278        let snapshot = self.snapshot(window, cx);
16279        let buffer = &snapshot.buffer_snapshot();
16280        let position = self.selections.newest::<Point>(cx).head();
16281        let anchor_position = buffer.anchor_after(position);
16282
16283        // Get all document highlights (both read and write)
16284        let mut all_highlights = Vec::new();
16285
16286        if let Some((_, read_highlights)) = self
16287            .background_highlights
16288            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16289        {
16290            all_highlights.extend(read_highlights.iter());
16291        }
16292
16293        if let Some((_, write_highlights)) = self
16294            .background_highlights
16295            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16296        {
16297            all_highlights.extend(write_highlights.iter());
16298        }
16299
16300        if all_highlights.is_empty() {
16301            return;
16302        }
16303
16304        // Sort highlights by position
16305        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16306
16307        let target_highlight = match direction {
16308            Direction::Next => {
16309                // Find the first highlight after the current position
16310                all_highlights
16311                    .iter()
16312                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16313            }
16314            Direction::Prev => {
16315                // Find the last highlight before the current position
16316                all_highlights
16317                    .iter()
16318                    .rev()
16319                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16320            }
16321        };
16322
16323        if let Some(highlight) = target_highlight {
16324            let destination = highlight.start.to_point(buffer);
16325            let autoscroll = Autoscroll::center();
16326
16327            self.unfold_ranges(&[destination..destination], false, false, cx);
16328            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16329                s.select_ranges([destination..destination]);
16330            });
16331        }
16332    }
16333
16334    fn go_to_line<T: 'static>(
16335        &mut self,
16336        position: Anchor,
16337        highlight_color: Option<Hsla>,
16338        window: &mut Window,
16339        cx: &mut Context<Self>,
16340    ) {
16341        let snapshot = self.snapshot(window, cx).display_snapshot;
16342        let position = position.to_point(&snapshot.buffer_snapshot());
16343        let start = snapshot
16344            .buffer_snapshot()
16345            .clip_point(Point::new(position.row, 0), Bias::Left);
16346        let end = start + Point::new(1, 0);
16347        let start = snapshot.buffer_snapshot().anchor_before(start);
16348        let end = snapshot.buffer_snapshot().anchor_before(end);
16349
16350        self.highlight_rows::<T>(
16351            start..end,
16352            highlight_color
16353                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16354            Default::default(),
16355            cx,
16356        );
16357
16358        if self.buffer.read(cx).is_singleton() {
16359            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16360        }
16361    }
16362
16363    pub fn go_to_definition(
16364        &mut self,
16365        _: &GoToDefinition,
16366        window: &mut Window,
16367        cx: &mut Context<Self>,
16368    ) -> Task<Result<Navigated>> {
16369        let definition =
16370            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16371        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16372        cx.spawn_in(window, async move |editor, cx| {
16373            if definition.await? == Navigated::Yes {
16374                return Ok(Navigated::Yes);
16375            }
16376            match fallback_strategy {
16377                GoToDefinitionFallback::None => Ok(Navigated::No),
16378                GoToDefinitionFallback::FindAllReferences => {
16379                    match editor.update_in(cx, |editor, window, cx| {
16380                        editor.find_all_references(&FindAllReferences, window, cx)
16381                    })? {
16382                        Some(references) => references.await,
16383                        None => Ok(Navigated::No),
16384                    }
16385                }
16386            }
16387        })
16388    }
16389
16390    pub fn go_to_declaration(
16391        &mut self,
16392        _: &GoToDeclaration,
16393        window: &mut Window,
16394        cx: &mut Context<Self>,
16395    ) -> Task<Result<Navigated>> {
16396        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16397    }
16398
16399    pub fn go_to_declaration_split(
16400        &mut self,
16401        _: &GoToDeclaration,
16402        window: &mut Window,
16403        cx: &mut Context<Self>,
16404    ) -> Task<Result<Navigated>> {
16405        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16406    }
16407
16408    pub fn go_to_implementation(
16409        &mut self,
16410        _: &GoToImplementation,
16411        window: &mut Window,
16412        cx: &mut Context<Self>,
16413    ) -> Task<Result<Navigated>> {
16414        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16415    }
16416
16417    pub fn go_to_implementation_split(
16418        &mut self,
16419        _: &GoToImplementationSplit,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) -> Task<Result<Navigated>> {
16423        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16424    }
16425
16426    pub fn go_to_type_definition(
16427        &mut self,
16428        _: &GoToTypeDefinition,
16429        window: &mut Window,
16430        cx: &mut Context<Self>,
16431    ) -> Task<Result<Navigated>> {
16432        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16433    }
16434
16435    pub fn go_to_definition_split(
16436        &mut self,
16437        _: &GoToDefinitionSplit,
16438        window: &mut Window,
16439        cx: &mut Context<Self>,
16440    ) -> Task<Result<Navigated>> {
16441        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16442    }
16443
16444    pub fn go_to_type_definition_split(
16445        &mut self,
16446        _: &GoToTypeDefinitionSplit,
16447        window: &mut Window,
16448        cx: &mut Context<Self>,
16449    ) -> Task<Result<Navigated>> {
16450        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16451    }
16452
16453    fn go_to_definition_of_kind(
16454        &mut self,
16455        kind: GotoDefinitionKind,
16456        split: bool,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) -> Task<Result<Navigated>> {
16460        let Some(provider) = self.semantics_provider.clone() else {
16461            return Task::ready(Ok(Navigated::No));
16462        };
16463        let head = self.selections.newest::<usize>(cx).head();
16464        let buffer = self.buffer.read(cx);
16465        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16466            return Task::ready(Ok(Navigated::No));
16467        };
16468        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16469            return Task::ready(Ok(Navigated::No));
16470        };
16471
16472        cx.spawn_in(window, async move |editor, cx| {
16473            let Some(definitions) = definitions.await? else {
16474                return Ok(Navigated::No);
16475            };
16476            let navigated = editor
16477                .update_in(cx, |editor, window, cx| {
16478                    editor.navigate_to_hover_links(
16479                        Some(kind),
16480                        definitions
16481                            .into_iter()
16482                            .filter(|location| {
16483                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16484                            })
16485                            .map(HoverLink::Text)
16486                            .collect::<Vec<_>>(),
16487                        split,
16488                        window,
16489                        cx,
16490                    )
16491                })?
16492                .await?;
16493            anyhow::Ok(navigated)
16494        })
16495    }
16496
16497    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16498        let selection = self.selections.newest_anchor();
16499        let head = selection.head();
16500        let tail = selection.tail();
16501
16502        let Some((buffer, start_position)) =
16503            self.buffer.read(cx).text_anchor_for_position(head, cx)
16504        else {
16505            return;
16506        };
16507
16508        let end_position = if head != tail {
16509            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16510                return;
16511            };
16512            Some(pos)
16513        } else {
16514            None
16515        };
16516
16517        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16518            let url = if let Some(end_pos) = end_position {
16519                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16520            } else {
16521                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16522            };
16523
16524            if let Some(url) = url {
16525                cx.update(|window, cx| {
16526                    if parse_zed_link(&url, cx).is_some() {
16527                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16528                    } else {
16529                        cx.open_url(&url);
16530                    }
16531                })?;
16532            }
16533
16534            anyhow::Ok(())
16535        });
16536
16537        url_finder.detach();
16538    }
16539
16540    pub fn open_selected_filename(
16541        &mut self,
16542        _: &OpenSelectedFilename,
16543        window: &mut Window,
16544        cx: &mut Context<Self>,
16545    ) {
16546        let Some(workspace) = self.workspace() else {
16547            return;
16548        };
16549
16550        let position = self.selections.newest_anchor().head();
16551
16552        let Some((buffer, buffer_position)) =
16553            self.buffer.read(cx).text_anchor_for_position(position, cx)
16554        else {
16555            return;
16556        };
16557
16558        let project = self.project.clone();
16559
16560        cx.spawn_in(window, async move |_, cx| {
16561            let result = find_file(&buffer, project, buffer_position, cx).await;
16562
16563            if let Some((_, path)) = result {
16564                workspace
16565                    .update_in(cx, |workspace, window, cx| {
16566                        workspace.open_resolved_path(path, window, cx)
16567                    })?
16568                    .await?;
16569            }
16570            anyhow::Ok(())
16571        })
16572        .detach();
16573    }
16574
16575    pub(crate) fn navigate_to_hover_links(
16576        &mut self,
16577        kind: Option<GotoDefinitionKind>,
16578        definitions: Vec<HoverLink>,
16579        split: bool,
16580        window: &mut Window,
16581        cx: &mut Context<Editor>,
16582    ) -> Task<Result<Navigated>> {
16583        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16584        let mut first_url_or_file = None;
16585        let definitions: Vec<_> = definitions
16586            .into_iter()
16587            .filter_map(|def| match def {
16588                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16589                HoverLink::InlayHint(lsp_location, server_id) => {
16590                    let computation =
16591                        self.compute_target_location(lsp_location, server_id, window, cx);
16592                    Some(cx.background_spawn(computation))
16593                }
16594                HoverLink::Url(url) => {
16595                    first_url_or_file = Some(Either::Left(url));
16596                    None
16597                }
16598                HoverLink::File(path) => {
16599                    first_url_or_file = Some(Either::Right(path));
16600                    None
16601                }
16602            })
16603            .collect();
16604
16605        let workspace = self.workspace();
16606
16607        cx.spawn_in(window, async move |editor, cx| {
16608            let locations: Vec<Location> = future::join_all(definitions)
16609                .await
16610                .into_iter()
16611                .filter_map(|location| location.transpose())
16612                .collect::<Result<_>>()
16613                .context("location tasks")?;
16614            let mut locations = cx.update(|_, cx| {
16615                locations
16616                    .into_iter()
16617                    .map(|location| {
16618                        let buffer = location.buffer.read(cx);
16619                        (location.buffer, location.range.to_point(buffer))
16620                    })
16621                    .into_group_map()
16622            })?;
16623            let mut num_locations = 0;
16624            for ranges in locations.values_mut() {
16625                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16626                ranges.dedup();
16627                num_locations += ranges.len();
16628            }
16629
16630            if num_locations > 1 {
16631                let Some(workspace) = workspace else {
16632                    return Ok(Navigated::No);
16633                };
16634
16635                let tab_kind = match kind {
16636                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16637                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16638                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16639                    Some(GotoDefinitionKind::Type) => "Types",
16640                };
16641                let title = editor
16642                    .update_in(cx, |_, _, cx| {
16643                        let target = locations
16644                            .iter()
16645                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16646                            .map(|(buffer, location)| {
16647                                buffer
16648                                    .read(cx)
16649                                    .text_for_range(location.clone())
16650                                    .collect::<String>()
16651                            })
16652                            .filter(|text| !text.contains('\n'))
16653                            .unique()
16654                            .take(3)
16655                            .join(", ");
16656                        if target.is_empty() {
16657                            tab_kind.to_owned()
16658                        } else {
16659                            format!("{tab_kind} for {target}")
16660                        }
16661                    })
16662                    .context("buffer title")?;
16663
16664                let opened = workspace
16665                    .update_in(cx, |workspace, window, cx| {
16666                        Self::open_locations_in_multibuffer(
16667                            workspace,
16668                            locations,
16669                            title,
16670                            split,
16671                            MultibufferSelectionMode::First,
16672                            window,
16673                            cx,
16674                        )
16675                    })
16676                    .is_ok();
16677
16678                anyhow::Ok(Navigated::from_bool(opened))
16679            } else if num_locations == 0 {
16680                // If there is one url or file, open it directly
16681                match first_url_or_file {
16682                    Some(Either::Left(url)) => {
16683                        cx.update(|_, cx| cx.open_url(&url))?;
16684                        Ok(Navigated::Yes)
16685                    }
16686                    Some(Either::Right(path)) => {
16687                        let Some(workspace) = workspace else {
16688                            return Ok(Navigated::No);
16689                        };
16690
16691                        workspace
16692                            .update_in(cx, |workspace, window, cx| {
16693                                workspace.open_resolved_path(path, window, cx)
16694                            })?
16695                            .await?;
16696                        Ok(Navigated::Yes)
16697                    }
16698                    None => Ok(Navigated::No),
16699                }
16700            } else {
16701                let Some(workspace) = workspace else {
16702                    return Ok(Navigated::No);
16703                };
16704
16705                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16706                let target_range = target_ranges.first().unwrap().clone();
16707
16708                editor.update_in(cx, |editor, window, cx| {
16709                    let range = target_range.to_point(target_buffer.read(cx));
16710                    let range = editor.range_for_match(&range);
16711                    let range = collapse_multiline_range(range);
16712
16713                    if !split
16714                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16715                    {
16716                        editor.go_to_singleton_buffer_range(range, window, cx);
16717                    } else {
16718                        let pane = workspace.read(cx).active_pane().clone();
16719                        window.defer(cx, move |window, cx| {
16720                            let target_editor: Entity<Self> =
16721                                workspace.update(cx, |workspace, cx| {
16722                                    let pane = if split {
16723                                        workspace.adjacent_pane(window, cx)
16724                                    } else {
16725                                        workspace.active_pane().clone()
16726                                    };
16727
16728                                    workspace.open_project_item(
16729                                        pane,
16730                                        target_buffer.clone(),
16731                                        true,
16732                                        true,
16733                                        window,
16734                                        cx,
16735                                    )
16736                                });
16737                            target_editor.update(cx, |target_editor, cx| {
16738                                // When selecting a definition in a different buffer, disable the nav history
16739                                // to avoid creating a history entry at the previous cursor location.
16740                                pane.update(cx, |pane, _| pane.disable_history());
16741                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16742                                pane.update(cx, |pane, _| pane.enable_history());
16743                            });
16744                        });
16745                    }
16746                    Navigated::Yes
16747                })
16748            }
16749        })
16750    }
16751
16752    fn compute_target_location(
16753        &self,
16754        lsp_location: lsp::Location,
16755        server_id: LanguageServerId,
16756        window: &mut Window,
16757        cx: &mut Context<Self>,
16758    ) -> Task<anyhow::Result<Option<Location>>> {
16759        let Some(project) = self.project.clone() else {
16760            return Task::ready(Ok(None));
16761        };
16762
16763        cx.spawn_in(window, async move |editor, cx| {
16764            let location_task = editor.update(cx, |_, cx| {
16765                project.update(cx, |project, cx| {
16766                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16767                })
16768            })?;
16769            let location = Some({
16770                let target_buffer_handle = location_task.await.context("open local buffer")?;
16771                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16772                    let target_start = target_buffer
16773                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16774                    let target_end = target_buffer
16775                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16776                    target_buffer.anchor_after(target_start)
16777                        ..target_buffer.anchor_before(target_end)
16778                })?;
16779                Location {
16780                    buffer: target_buffer_handle,
16781                    range,
16782                }
16783            });
16784            Ok(location)
16785        })
16786    }
16787
16788    pub fn find_all_references(
16789        &mut self,
16790        _: &FindAllReferences,
16791        window: &mut Window,
16792        cx: &mut Context<Self>,
16793    ) -> Option<Task<Result<Navigated>>> {
16794        let selection = self.selections.newest::<usize>(cx);
16795        let multi_buffer = self.buffer.read(cx);
16796        let head = selection.head();
16797
16798        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16799        let head_anchor = multi_buffer_snapshot.anchor_at(
16800            head,
16801            if head < selection.tail() {
16802                Bias::Right
16803            } else {
16804                Bias::Left
16805            },
16806        );
16807
16808        match self
16809            .find_all_references_task_sources
16810            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16811        {
16812            Ok(_) => {
16813                log::info!(
16814                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16815                );
16816                return None;
16817            }
16818            Err(i) => {
16819                self.find_all_references_task_sources.insert(i, head_anchor);
16820            }
16821        }
16822
16823        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16824        let workspace = self.workspace()?;
16825        let project = workspace.read(cx).project().clone();
16826        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16827        Some(cx.spawn_in(window, async move |editor, cx| {
16828            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16829                if let Ok(i) = editor
16830                    .find_all_references_task_sources
16831                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16832                {
16833                    editor.find_all_references_task_sources.remove(i);
16834                }
16835            });
16836
16837            let Some(locations) = references.await? else {
16838                return anyhow::Ok(Navigated::No);
16839            };
16840            let mut locations = cx.update(|_, cx| {
16841                locations
16842                    .into_iter()
16843                    .map(|location| {
16844                        let buffer = location.buffer.read(cx);
16845                        (location.buffer, location.range.to_point(buffer))
16846                    })
16847                    .into_group_map()
16848            })?;
16849            if locations.is_empty() {
16850                return anyhow::Ok(Navigated::No);
16851            }
16852            for ranges in locations.values_mut() {
16853                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16854                ranges.dedup();
16855            }
16856
16857            workspace.update_in(cx, |workspace, window, cx| {
16858                let target = locations
16859                    .iter()
16860                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16861                    .map(|(buffer, location)| {
16862                        buffer
16863                            .read(cx)
16864                            .text_for_range(location.clone())
16865                            .collect::<String>()
16866                    })
16867                    .filter(|text| !text.contains('\n'))
16868                    .unique()
16869                    .take(3)
16870                    .join(", ");
16871                let title = if target.is_empty() {
16872                    "References".to_owned()
16873                } else {
16874                    format!("References to {target}")
16875                };
16876                Self::open_locations_in_multibuffer(
16877                    workspace,
16878                    locations,
16879                    title,
16880                    false,
16881                    MultibufferSelectionMode::First,
16882                    window,
16883                    cx,
16884                );
16885                Navigated::Yes
16886            })
16887        }))
16888    }
16889
16890    /// Opens a multibuffer with the given project locations in it
16891    pub fn open_locations_in_multibuffer(
16892        workspace: &mut Workspace,
16893        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16894        title: String,
16895        split: bool,
16896        multibuffer_selection_mode: MultibufferSelectionMode,
16897        window: &mut Window,
16898        cx: &mut Context<Workspace>,
16899    ) {
16900        if locations.is_empty() {
16901            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16902            return;
16903        }
16904
16905        let capability = workspace.project().read(cx).capability();
16906        let mut ranges = <Vec<Range<Anchor>>>::new();
16907
16908        // a key to find existing multibuffer editors with the same set of locations
16909        // to prevent us from opening more and more multibuffer tabs for searches and the like
16910        let mut key = (title.clone(), vec![]);
16911        let excerpt_buffer = cx.new(|cx| {
16912            let key = &mut key.1;
16913            let mut multibuffer = MultiBuffer::new(capability);
16914            for (buffer, mut ranges_for_buffer) in locations {
16915                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16916                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16917                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16918                    PathKey::for_buffer(&buffer, cx),
16919                    buffer.clone(),
16920                    ranges_for_buffer,
16921                    multibuffer_context_lines(cx),
16922                    cx,
16923                );
16924                ranges.extend(new_ranges)
16925            }
16926
16927            multibuffer.with_title(title)
16928        });
16929        let existing = workspace.active_pane().update(cx, |pane, cx| {
16930            pane.items()
16931                .filter_map(|item| item.downcast::<Editor>())
16932                .find(|editor| {
16933                    editor
16934                        .read(cx)
16935                        .lookup_key
16936                        .as_ref()
16937                        .and_then(|it| {
16938                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16939                        })
16940                        .is_some_and(|it| *it == key)
16941                })
16942        });
16943        let editor = existing.unwrap_or_else(|| {
16944            cx.new(|cx| {
16945                let mut editor = Editor::for_multibuffer(
16946                    excerpt_buffer,
16947                    Some(workspace.project().clone()),
16948                    window,
16949                    cx,
16950                );
16951                editor.lookup_key = Some(Box::new(key));
16952                editor
16953            })
16954        });
16955        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
16956            MultibufferSelectionMode::First => {
16957                if let Some(first_range) = ranges.first() {
16958                    editor.change_selections(
16959                        SelectionEffects::no_scroll(),
16960                        window,
16961                        cx,
16962                        |selections| {
16963                            selections.clear_disjoint();
16964                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
16965                        },
16966                    );
16967                }
16968                editor.highlight_background::<Self>(
16969                    &ranges,
16970                    |theme| theme.colors().editor_highlighted_line_background,
16971                    cx,
16972                );
16973            }
16974            MultibufferSelectionMode::All => {
16975                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16976                    selections.clear_disjoint();
16977                    selections.select_anchor_ranges(ranges);
16978                });
16979            }
16980        });
16981
16982        let item = Box::new(editor);
16983        let item_id = item.item_id();
16984
16985        if split {
16986            let pane = workspace.adjacent_pane(window, cx);
16987            workspace.add_item(pane, item, None, true, true, window, cx);
16988        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16989            let (preview_item_id, preview_item_idx) =
16990                workspace.active_pane().read_with(cx, |pane, _| {
16991                    (pane.preview_item_id(), pane.preview_item_idx())
16992                });
16993
16994            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16995
16996            if let Some(preview_item_id) = preview_item_id {
16997                workspace.active_pane().update(cx, |pane, cx| {
16998                    pane.remove_item(preview_item_id, false, false, window, cx);
16999                });
17000            }
17001        } else {
17002            workspace.add_item_to_active_pane(item, None, true, window, cx);
17003        }
17004        workspace.active_pane().update(cx, |pane, cx| {
17005            pane.set_preview_item_id(Some(item_id), cx);
17006        });
17007    }
17008
17009    pub fn rename(
17010        &mut self,
17011        _: &Rename,
17012        window: &mut Window,
17013        cx: &mut Context<Self>,
17014    ) -> Option<Task<Result<()>>> {
17015        use language::ToOffset as _;
17016
17017        let provider = self.semantics_provider.clone()?;
17018        let selection = self.selections.newest_anchor().clone();
17019        let (cursor_buffer, cursor_buffer_position) = self
17020            .buffer
17021            .read(cx)
17022            .text_anchor_for_position(selection.head(), cx)?;
17023        let (tail_buffer, cursor_buffer_position_end) = self
17024            .buffer
17025            .read(cx)
17026            .text_anchor_for_position(selection.tail(), cx)?;
17027        if tail_buffer != cursor_buffer {
17028            return None;
17029        }
17030
17031        let snapshot = cursor_buffer.read(cx).snapshot();
17032        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17033        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17034        let prepare_rename = provider
17035            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17036            .unwrap_or_else(|| Task::ready(Ok(None)));
17037        drop(snapshot);
17038
17039        Some(cx.spawn_in(window, async move |this, cx| {
17040            let rename_range = if let Some(range) = prepare_rename.await? {
17041                Some(range)
17042            } else {
17043                this.update(cx, |this, cx| {
17044                    let buffer = this.buffer.read(cx).snapshot(cx);
17045                    let mut buffer_highlights = this
17046                        .document_highlights_for_position(selection.head(), &buffer)
17047                        .filter(|highlight| {
17048                            highlight.start.excerpt_id == selection.head().excerpt_id
17049                                && highlight.end.excerpt_id == selection.head().excerpt_id
17050                        });
17051                    buffer_highlights
17052                        .next()
17053                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17054                })?
17055            };
17056            if let Some(rename_range) = rename_range {
17057                this.update_in(cx, |this, window, cx| {
17058                    let snapshot = cursor_buffer.read(cx).snapshot();
17059                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17060                    let cursor_offset_in_rename_range =
17061                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17062                    let cursor_offset_in_rename_range_end =
17063                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17064
17065                    this.take_rename(false, window, cx);
17066                    let buffer = this.buffer.read(cx).read(cx);
17067                    let cursor_offset = selection.head().to_offset(&buffer);
17068                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17069                    let rename_end = rename_start + rename_buffer_range.len();
17070                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17071                    let mut old_highlight_id = None;
17072                    let old_name: Arc<str> = buffer
17073                        .chunks(rename_start..rename_end, true)
17074                        .map(|chunk| {
17075                            if old_highlight_id.is_none() {
17076                                old_highlight_id = chunk.syntax_highlight_id;
17077                            }
17078                            chunk.text
17079                        })
17080                        .collect::<String>()
17081                        .into();
17082
17083                    drop(buffer);
17084
17085                    // Position the selection in the rename editor so that it matches the current selection.
17086                    this.show_local_selections = false;
17087                    let rename_editor = cx.new(|cx| {
17088                        let mut editor = Editor::single_line(window, cx);
17089                        editor.buffer.update(cx, |buffer, cx| {
17090                            buffer.edit([(0..0, old_name.clone())], None, cx)
17091                        });
17092                        let rename_selection_range = match cursor_offset_in_rename_range
17093                            .cmp(&cursor_offset_in_rename_range_end)
17094                        {
17095                            Ordering::Equal => {
17096                                editor.select_all(&SelectAll, window, cx);
17097                                return editor;
17098                            }
17099                            Ordering::Less => {
17100                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17101                            }
17102                            Ordering::Greater => {
17103                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17104                            }
17105                        };
17106                        if rename_selection_range.end > old_name.len() {
17107                            editor.select_all(&SelectAll, window, cx);
17108                        } else {
17109                            editor.change_selections(Default::default(), window, cx, |s| {
17110                                s.select_ranges([rename_selection_range]);
17111                            });
17112                        }
17113                        editor
17114                    });
17115                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17116                        if e == &EditorEvent::Focused {
17117                            cx.emit(EditorEvent::FocusedIn)
17118                        }
17119                    })
17120                    .detach();
17121
17122                    let write_highlights =
17123                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17124                    let read_highlights =
17125                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17126                    let ranges = write_highlights
17127                        .iter()
17128                        .flat_map(|(_, ranges)| ranges.iter())
17129                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17130                        .cloned()
17131                        .collect();
17132
17133                    this.highlight_text::<Rename>(
17134                        ranges,
17135                        HighlightStyle {
17136                            fade_out: Some(0.6),
17137                            ..Default::default()
17138                        },
17139                        cx,
17140                    );
17141                    let rename_focus_handle = rename_editor.focus_handle(cx);
17142                    window.focus(&rename_focus_handle);
17143                    let block_id = this.insert_blocks(
17144                        [BlockProperties {
17145                            style: BlockStyle::Flex,
17146                            placement: BlockPlacement::Below(range.start),
17147                            height: Some(1),
17148                            render: Arc::new({
17149                                let rename_editor = rename_editor.clone();
17150                                move |cx: &mut BlockContext| {
17151                                    let mut text_style = cx.editor_style.text.clone();
17152                                    if let Some(highlight_style) = old_highlight_id
17153                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17154                                    {
17155                                        text_style = text_style.highlight(highlight_style);
17156                                    }
17157                                    div()
17158                                        .block_mouse_except_scroll()
17159                                        .pl(cx.anchor_x)
17160                                        .child(EditorElement::new(
17161                                            &rename_editor,
17162                                            EditorStyle {
17163                                                background: cx.theme().system().transparent,
17164                                                local_player: cx.editor_style.local_player,
17165                                                text: text_style,
17166                                                scrollbar_width: cx.editor_style.scrollbar_width,
17167                                                syntax: cx.editor_style.syntax.clone(),
17168                                                status: cx.editor_style.status.clone(),
17169                                                inlay_hints_style: HighlightStyle {
17170                                                    font_weight: Some(FontWeight::BOLD),
17171                                                    ..make_inlay_hints_style(cx.app)
17172                                                },
17173                                                edit_prediction_styles: make_suggestion_styles(
17174                                                    cx.app,
17175                                                ),
17176                                                ..EditorStyle::default()
17177                                            },
17178                                        ))
17179                                        .into_any_element()
17180                                }
17181                            }),
17182                            priority: 0,
17183                        }],
17184                        Some(Autoscroll::fit()),
17185                        cx,
17186                    )[0];
17187                    this.pending_rename = Some(RenameState {
17188                        range,
17189                        old_name,
17190                        editor: rename_editor,
17191                        block_id,
17192                    });
17193                })?;
17194            }
17195
17196            Ok(())
17197        }))
17198    }
17199
17200    pub fn confirm_rename(
17201        &mut self,
17202        _: &ConfirmRename,
17203        window: &mut Window,
17204        cx: &mut Context<Self>,
17205    ) -> Option<Task<Result<()>>> {
17206        let rename = self.take_rename(false, window, cx)?;
17207        let workspace = self.workspace()?.downgrade();
17208        let (buffer, start) = self
17209            .buffer
17210            .read(cx)
17211            .text_anchor_for_position(rename.range.start, cx)?;
17212        let (end_buffer, _) = self
17213            .buffer
17214            .read(cx)
17215            .text_anchor_for_position(rename.range.end, cx)?;
17216        if buffer != end_buffer {
17217            return None;
17218        }
17219
17220        let old_name = rename.old_name;
17221        let new_name = rename.editor.read(cx).text(cx);
17222
17223        let rename = self.semantics_provider.as_ref()?.perform_rename(
17224            &buffer,
17225            start,
17226            new_name.clone(),
17227            cx,
17228        )?;
17229
17230        Some(cx.spawn_in(window, async move |editor, cx| {
17231            let project_transaction = rename.await?;
17232            Self::open_project_transaction(
17233                &editor,
17234                workspace,
17235                project_transaction,
17236                format!("Rename: {}{}", old_name, new_name),
17237                cx,
17238            )
17239            .await?;
17240
17241            editor.update(cx, |editor, cx| {
17242                editor.refresh_document_highlights(cx);
17243            })?;
17244            Ok(())
17245        }))
17246    }
17247
17248    fn take_rename(
17249        &mut self,
17250        moving_cursor: bool,
17251        window: &mut Window,
17252        cx: &mut Context<Self>,
17253    ) -> Option<RenameState> {
17254        let rename = self.pending_rename.take()?;
17255        if rename.editor.focus_handle(cx).is_focused(window) {
17256            window.focus(&self.focus_handle);
17257        }
17258
17259        self.remove_blocks(
17260            [rename.block_id].into_iter().collect(),
17261            Some(Autoscroll::fit()),
17262            cx,
17263        );
17264        self.clear_highlights::<Rename>(cx);
17265        self.show_local_selections = true;
17266
17267        if moving_cursor {
17268            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17269                editor.selections.newest::<usize>(cx).head()
17270            });
17271
17272            // Update the selection to match the position of the selection inside
17273            // the rename editor.
17274            let snapshot = self.buffer.read(cx).read(cx);
17275            let rename_range = rename.range.to_offset(&snapshot);
17276            let cursor_in_editor = snapshot
17277                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17278                .min(rename_range.end);
17279            drop(snapshot);
17280
17281            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17282                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17283            });
17284        } else {
17285            self.refresh_document_highlights(cx);
17286        }
17287
17288        Some(rename)
17289    }
17290
17291    pub fn pending_rename(&self) -> Option<&RenameState> {
17292        self.pending_rename.as_ref()
17293    }
17294
17295    fn format(
17296        &mut self,
17297        _: &Format,
17298        window: &mut Window,
17299        cx: &mut Context<Self>,
17300    ) -> Option<Task<Result<()>>> {
17301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17302
17303        let project = match &self.project {
17304            Some(project) => project.clone(),
17305            None => return None,
17306        };
17307
17308        Some(self.perform_format(
17309            project,
17310            FormatTrigger::Manual,
17311            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17312            window,
17313            cx,
17314        ))
17315    }
17316
17317    fn format_selections(
17318        &mut self,
17319        _: &FormatSelections,
17320        window: &mut Window,
17321        cx: &mut Context<Self>,
17322    ) -> Option<Task<Result<()>>> {
17323        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17324
17325        let project = match &self.project {
17326            Some(project) => project.clone(),
17327            None => return None,
17328        };
17329
17330        let ranges = self
17331            .selections
17332            .all_adjusted(cx)
17333            .into_iter()
17334            .map(|selection| selection.range())
17335            .collect_vec();
17336
17337        Some(self.perform_format(
17338            project,
17339            FormatTrigger::Manual,
17340            FormatTarget::Ranges(ranges),
17341            window,
17342            cx,
17343        ))
17344    }
17345
17346    fn perform_format(
17347        &mut self,
17348        project: Entity<Project>,
17349        trigger: FormatTrigger,
17350        target: FormatTarget,
17351        window: &mut Window,
17352        cx: &mut Context<Self>,
17353    ) -> Task<Result<()>> {
17354        let buffer = self.buffer.clone();
17355        let (buffers, target) = match target {
17356            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17357            FormatTarget::Ranges(selection_ranges) => {
17358                let multi_buffer = buffer.read(cx);
17359                let snapshot = multi_buffer.read(cx);
17360                let mut buffers = HashSet::default();
17361                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17362                    BTreeMap::new();
17363                for selection_range in selection_ranges {
17364                    for (buffer, buffer_range, _) in
17365                        snapshot.range_to_buffer_ranges(selection_range)
17366                    {
17367                        let buffer_id = buffer.remote_id();
17368                        let start = buffer.anchor_before(buffer_range.start);
17369                        let end = buffer.anchor_after(buffer_range.end);
17370                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17371                        buffer_id_to_ranges
17372                            .entry(buffer_id)
17373                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17374                            .or_insert_with(|| vec![start..end]);
17375                    }
17376                }
17377                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17378            }
17379        };
17380
17381        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17382        let selections_prev = transaction_id_prev
17383            .and_then(|transaction_id_prev| {
17384                // default to selections as they were after the last edit, if we have them,
17385                // instead of how they are now.
17386                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17387                // will take you back to where you made the last edit, instead of staying where you scrolled
17388                self.selection_history
17389                    .transaction(transaction_id_prev)
17390                    .map(|t| t.0.clone())
17391            })
17392            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17393
17394        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17395        let format = project.update(cx, |project, cx| {
17396            project.format(buffers, target, true, trigger, cx)
17397        });
17398
17399        cx.spawn_in(window, async move |editor, cx| {
17400            let transaction = futures::select_biased! {
17401                transaction = format.log_err().fuse() => transaction,
17402                () = timeout => {
17403                    log::warn!("timed out waiting for formatting");
17404                    None
17405                }
17406            };
17407
17408            buffer
17409                .update(cx, |buffer, cx| {
17410                    if let Some(transaction) = transaction
17411                        && !buffer.is_singleton()
17412                    {
17413                        buffer.push_transaction(&transaction.0, cx);
17414                    }
17415                    cx.notify();
17416                })
17417                .ok();
17418
17419            if let Some(transaction_id_now) =
17420                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17421            {
17422                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17423                if has_new_transaction {
17424                    _ = editor.update(cx, |editor, _| {
17425                        editor
17426                            .selection_history
17427                            .insert_transaction(transaction_id_now, selections_prev);
17428                    });
17429                }
17430            }
17431
17432            Ok(())
17433        })
17434    }
17435
17436    fn organize_imports(
17437        &mut self,
17438        _: &OrganizeImports,
17439        window: &mut Window,
17440        cx: &mut Context<Self>,
17441    ) -> Option<Task<Result<()>>> {
17442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17443        let project = match &self.project {
17444            Some(project) => project.clone(),
17445            None => return None,
17446        };
17447        Some(self.perform_code_action_kind(
17448            project,
17449            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17450            window,
17451            cx,
17452        ))
17453    }
17454
17455    fn perform_code_action_kind(
17456        &mut self,
17457        project: Entity<Project>,
17458        kind: CodeActionKind,
17459        window: &mut Window,
17460        cx: &mut Context<Self>,
17461    ) -> Task<Result<()>> {
17462        let buffer = self.buffer.clone();
17463        let buffers = buffer.read(cx).all_buffers();
17464        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17465        let apply_action = project.update(cx, |project, cx| {
17466            project.apply_code_action_kind(buffers, kind, true, cx)
17467        });
17468        cx.spawn_in(window, async move |_, cx| {
17469            let transaction = futures::select_biased! {
17470                () = timeout => {
17471                    log::warn!("timed out waiting for executing code action");
17472                    None
17473                }
17474                transaction = apply_action.log_err().fuse() => transaction,
17475            };
17476            buffer
17477                .update(cx, |buffer, cx| {
17478                    // check if we need this
17479                    if let Some(transaction) = transaction
17480                        && !buffer.is_singleton()
17481                    {
17482                        buffer.push_transaction(&transaction.0, cx);
17483                    }
17484                    cx.notify();
17485                })
17486                .ok();
17487            Ok(())
17488        })
17489    }
17490
17491    pub fn restart_language_server(
17492        &mut self,
17493        _: &RestartLanguageServer,
17494        _: &mut Window,
17495        cx: &mut Context<Self>,
17496    ) {
17497        if let Some(project) = self.project.clone() {
17498            self.buffer.update(cx, |multi_buffer, cx| {
17499                project.update(cx, |project, cx| {
17500                    project.restart_language_servers_for_buffers(
17501                        multi_buffer.all_buffers().into_iter().collect(),
17502                        HashSet::default(),
17503                        cx,
17504                    );
17505                });
17506            })
17507        }
17508    }
17509
17510    pub fn stop_language_server(
17511        &mut self,
17512        _: &StopLanguageServer,
17513        _: &mut Window,
17514        cx: &mut Context<Self>,
17515    ) {
17516        if let Some(project) = self.project.clone() {
17517            self.buffer.update(cx, |multi_buffer, cx| {
17518                project.update(cx, |project, cx| {
17519                    project.stop_language_servers_for_buffers(
17520                        multi_buffer.all_buffers().into_iter().collect(),
17521                        HashSet::default(),
17522                        cx,
17523                    );
17524                    cx.emit(project::Event::RefreshInlayHints);
17525                });
17526            });
17527        }
17528    }
17529
17530    fn cancel_language_server_work(
17531        workspace: &mut Workspace,
17532        _: &actions::CancelLanguageServerWork,
17533        _: &mut Window,
17534        cx: &mut Context<Workspace>,
17535    ) {
17536        let project = workspace.project();
17537        let buffers = workspace
17538            .active_item(cx)
17539            .and_then(|item| item.act_as::<Editor>(cx))
17540            .map_or(HashSet::default(), |editor| {
17541                editor.read(cx).buffer.read(cx).all_buffers()
17542            });
17543        project.update(cx, |project, cx| {
17544            project.cancel_language_server_work_for_buffers(buffers, cx);
17545        });
17546    }
17547
17548    fn show_character_palette(
17549        &mut self,
17550        _: &ShowCharacterPalette,
17551        window: &mut Window,
17552        _: &mut Context<Self>,
17553    ) {
17554        window.show_character_palette();
17555    }
17556
17557    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17558        if !self.diagnostics_enabled() {
17559            return;
17560        }
17561
17562        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17563            let buffer = self.buffer.read(cx).snapshot(cx);
17564            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17565            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17566            let is_valid = buffer
17567                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17568                .any(|entry| {
17569                    entry.diagnostic.is_primary
17570                        && !entry.range.is_empty()
17571                        && entry.range.start == primary_range_start
17572                        && entry.diagnostic.message == active_diagnostics.active_message
17573                });
17574
17575            if !is_valid {
17576                self.dismiss_diagnostics(cx);
17577            }
17578        }
17579    }
17580
17581    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17582        match &self.active_diagnostics {
17583            ActiveDiagnostic::Group(group) => Some(group),
17584            _ => None,
17585        }
17586    }
17587
17588    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17589        if !self.diagnostics_enabled() {
17590            return;
17591        }
17592        self.dismiss_diagnostics(cx);
17593        self.active_diagnostics = ActiveDiagnostic::All;
17594    }
17595
17596    fn activate_diagnostics(
17597        &mut self,
17598        buffer_id: BufferId,
17599        diagnostic: DiagnosticEntryRef<'_, usize>,
17600        window: &mut Window,
17601        cx: &mut Context<Self>,
17602    ) {
17603        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17604            return;
17605        }
17606        self.dismiss_diagnostics(cx);
17607        let snapshot = self.snapshot(window, cx);
17608        let buffer = self.buffer.read(cx).snapshot(cx);
17609        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17610            return;
17611        };
17612
17613        let diagnostic_group = buffer
17614            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17615            .collect::<Vec<_>>();
17616
17617        let blocks =
17618            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17619
17620        let blocks = self.display_map.update(cx, |display_map, cx| {
17621            display_map.insert_blocks(blocks, cx).into_iter().collect()
17622        });
17623        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17624            active_range: buffer.anchor_before(diagnostic.range.start)
17625                ..buffer.anchor_after(diagnostic.range.end),
17626            active_message: diagnostic.diagnostic.message.clone(),
17627            group_id: diagnostic.diagnostic.group_id,
17628            blocks,
17629        });
17630        cx.notify();
17631    }
17632
17633    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17634        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17635            return;
17636        };
17637
17638        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17639        if let ActiveDiagnostic::Group(group) = prev {
17640            self.display_map.update(cx, |display_map, cx| {
17641                display_map.remove_blocks(group.blocks, cx);
17642            });
17643            cx.notify();
17644        }
17645    }
17646
17647    /// Disable inline diagnostics rendering for this editor.
17648    pub fn disable_inline_diagnostics(&mut self) {
17649        self.inline_diagnostics_enabled = false;
17650        self.inline_diagnostics_update = Task::ready(());
17651        self.inline_diagnostics.clear();
17652    }
17653
17654    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17655        self.diagnostics_enabled = false;
17656        self.dismiss_diagnostics(cx);
17657        self.inline_diagnostics_update = Task::ready(());
17658        self.inline_diagnostics.clear();
17659    }
17660
17661    pub fn disable_word_completions(&mut self) {
17662        self.word_completions_enabled = false;
17663    }
17664
17665    pub fn diagnostics_enabled(&self) -> bool {
17666        self.diagnostics_enabled && self.mode.is_full()
17667    }
17668
17669    pub fn inline_diagnostics_enabled(&self) -> bool {
17670        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17671    }
17672
17673    pub fn show_inline_diagnostics(&self) -> bool {
17674        self.show_inline_diagnostics
17675    }
17676
17677    pub fn toggle_inline_diagnostics(
17678        &mut self,
17679        _: &ToggleInlineDiagnostics,
17680        window: &mut Window,
17681        cx: &mut Context<Editor>,
17682    ) {
17683        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17684        self.refresh_inline_diagnostics(false, window, cx);
17685    }
17686
17687    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17688        self.diagnostics_max_severity = severity;
17689        self.display_map.update(cx, |display_map, _| {
17690            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17691        });
17692    }
17693
17694    pub fn toggle_diagnostics(
17695        &mut self,
17696        _: &ToggleDiagnostics,
17697        window: &mut Window,
17698        cx: &mut Context<Editor>,
17699    ) {
17700        if !self.diagnostics_enabled() {
17701            return;
17702        }
17703
17704        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17705            EditorSettings::get_global(cx)
17706                .diagnostics_max_severity
17707                .filter(|severity| severity != &DiagnosticSeverity::Off)
17708                .unwrap_or(DiagnosticSeverity::Hint)
17709        } else {
17710            DiagnosticSeverity::Off
17711        };
17712        self.set_max_diagnostics_severity(new_severity, cx);
17713        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17714            self.active_diagnostics = ActiveDiagnostic::None;
17715            self.inline_diagnostics_update = Task::ready(());
17716            self.inline_diagnostics.clear();
17717        } else {
17718            self.refresh_inline_diagnostics(false, window, cx);
17719        }
17720
17721        cx.notify();
17722    }
17723
17724    pub fn toggle_minimap(
17725        &mut self,
17726        _: &ToggleMinimap,
17727        window: &mut Window,
17728        cx: &mut Context<Editor>,
17729    ) {
17730        if self.supports_minimap(cx) {
17731            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17732        }
17733    }
17734
17735    fn refresh_inline_diagnostics(
17736        &mut self,
17737        debounce: bool,
17738        window: &mut Window,
17739        cx: &mut Context<Self>,
17740    ) {
17741        let max_severity = ProjectSettings::get_global(cx)
17742            .diagnostics
17743            .inline
17744            .max_severity
17745            .unwrap_or(self.diagnostics_max_severity);
17746
17747        if !self.inline_diagnostics_enabled()
17748            || !self.show_inline_diagnostics
17749            || max_severity == DiagnosticSeverity::Off
17750        {
17751            self.inline_diagnostics_update = Task::ready(());
17752            self.inline_diagnostics.clear();
17753            return;
17754        }
17755
17756        let debounce_ms = ProjectSettings::get_global(cx)
17757            .diagnostics
17758            .inline
17759            .update_debounce_ms;
17760        let debounce = if debounce && debounce_ms > 0 {
17761            Some(Duration::from_millis(debounce_ms))
17762        } else {
17763            None
17764        };
17765        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17766            if let Some(debounce) = debounce {
17767                cx.background_executor().timer(debounce).await;
17768            }
17769            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17770                editor
17771                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17772                    .ok()
17773            }) else {
17774                return;
17775            };
17776
17777            let new_inline_diagnostics = cx
17778                .background_spawn(async move {
17779                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17780                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17781                        let message = diagnostic_entry
17782                            .diagnostic
17783                            .message
17784                            .split_once('\n')
17785                            .map(|(line, _)| line)
17786                            .map(SharedString::new)
17787                            .unwrap_or_else(|| {
17788                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17789                            });
17790                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17791                        let (Ok(i) | Err(i)) = inline_diagnostics
17792                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17793                        inline_diagnostics.insert(
17794                            i,
17795                            (
17796                                start_anchor,
17797                                InlineDiagnostic {
17798                                    message,
17799                                    group_id: diagnostic_entry.diagnostic.group_id,
17800                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17801                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17802                                    severity: diagnostic_entry.diagnostic.severity,
17803                                },
17804                            ),
17805                        );
17806                    }
17807                    inline_diagnostics
17808                })
17809                .await;
17810
17811            editor
17812                .update(cx, |editor, cx| {
17813                    editor.inline_diagnostics = new_inline_diagnostics;
17814                    cx.notify();
17815                })
17816                .ok();
17817        });
17818    }
17819
17820    fn pull_diagnostics(
17821        &mut self,
17822        buffer_id: Option<BufferId>,
17823        window: &Window,
17824        cx: &mut Context<Self>,
17825    ) -> Option<()> {
17826        if self.ignore_lsp_data() {
17827            return None;
17828        }
17829        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17830            .diagnostics
17831            .lsp_pull_diagnostics;
17832        if !pull_diagnostics_settings.enabled {
17833            return None;
17834        }
17835        let project = self.project()?.downgrade();
17836        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17837        let mut buffers = self.buffer.read(cx).all_buffers();
17838        buffers.retain(|buffer| {
17839            let buffer_id_to_retain = buffer.read(cx).remote_id();
17840            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17841                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17842        });
17843        if buffers.is_empty() {
17844            self.pull_diagnostics_task = Task::ready(());
17845            return None;
17846        }
17847
17848        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17849            cx.background_executor().timer(debounce).await;
17850
17851            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17852                buffers
17853                    .into_iter()
17854                    .filter_map(|buffer| {
17855                        project
17856                            .update(cx, |project, cx| {
17857                                project.lsp_store().update(cx, |lsp_store, cx| {
17858                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17859                                })
17860                            })
17861                            .ok()
17862                    })
17863                    .collect::<FuturesUnordered<_>>()
17864            }) else {
17865                return;
17866            };
17867
17868            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17869                match pull_task {
17870                    Ok(()) => {
17871                        if editor
17872                            .update_in(cx, |editor, window, cx| {
17873                                editor.update_diagnostics_state(window, cx);
17874                            })
17875                            .is_err()
17876                        {
17877                            return;
17878                        }
17879                    }
17880                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17881                }
17882            }
17883        });
17884
17885        Some(())
17886    }
17887
17888    pub fn set_selections_from_remote(
17889        &mut self,
17890        selections: Vec<Selection<Anchor>>,
17891        pending_selection: Option<Selection<Anchor>>,
17892        window: &mut Window,
17893        cx: &mut Context<Self>,
17894    ) {
17895        let old_cursor_position = self.selections.newest_anchor().head();
17896        self.selections.change_with(cx, |s| {
17897            s.select_anchors(selections);
17898            if let Some(pending_selection) = pending_selection {
17899                s.set_pending(pending_selection, SelectMode::Character);
17900            } else {
17901                s.clear_pending();
17902            }
17903        });
17904        self.selections_did_change(
17905            false,
17906            &old_cursor_position,
17907            SelectionEffects::default(),
17908            window,
17909            cx,
17910        );
17911    }
17912
17913    pub fn transact(
17914        &mut self,
17915        window: &mut Window,
17916        cx: &mut Context<Self>,
17917        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17918    ) -> Option<TransactionId> {
17919        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17920            this.start_transaction_at(Instant::now(), window, cx);
17921            update(this, window, cx);
17922            this.end_transaction_at(Instant::now(), cx)
17923        })
17924    }
17925
17926    pub fn start_transaction_at(
17927        &mut self,
17928        now: Instant,
17929        window: &mut Window,
17930        cx: &mut Context<Self>,
17931    ) -> Option<TransactionId> {
17932        self.end_selection(window, cx);
17933        if let Some(tx_id) = self
17934            .buffer
17935            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17936        {
17937            self.selection_history
17938                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17939            cx.emit(EditorEvent::TransactionBegun {
17940                transaction_id: tx_id,
17941            });
17942            Some(tx_id)
17943        } else {
17944            None
17945        }
17946    }
17947
17948    pub fn end_transaction_at(
17949        &mut self,
17950        now: Instant,
17951        cx: &mut Context<Self>,
17952    ) -> Option<TransactionId> {
17953        if let Some(transaction_id) = self
17954            .buffer
17955            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17956        {
17957            if let Some((_, end_selections)) =
17958                self.selection_history.transaction_mut(transaction_id)
17959            {
17960                *end_selections = Some(self.selections.disjoint_anchors_arc());
17961            } else {
17962                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17963            }
17964
17965            cx.emit(EditorEvent::Edited { transaction_id });
17966            Some(transaction_id)
17967        } else {
17968            None
17969        }
17970    }
17971
17972    pub fn modify_transaction_selection_history(
17973        &mut self,
17974        transaction_id: TransactionId,
17975        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17976    ) -> bool {
17977        self.selection_history
17978            .transaction_mut(transaction_id)
17979            .map(modify)
17980            .is_some()
17981    }
17982
17983    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17984        if self.selection_mark_mode {
17985            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17986                s.move_with(|_, sel| {
17987                    sel.collapse_to(sel.head(), SelectionGoal::None);
17988                });
17989            })
17990        }
17991        self.selection_mark_mode = true;
17992        cx.notify();
17993    }
17994
17995    pub fn swap_selection_ends(
17996        &mut self,
17997        _: &actions::SwapSelectionEnds,
17998        window: &mut Window,
17999        cx: &mut Context<Self>,
18000    ) {
18001        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18002            s.move_with(|_, sel| {
18003                if sel.start != sel.end {
18004                    sel.reversed = !sel.reversed
18005                }
18006            });
18007        });
18008        self.request_autoscroll(Autoscroll::newest(), cx);
18009        cx.notify();
18010    }
18011
18012    pub fn toggle_focus(
18013        workspace: &mut Workspace,
18014        _: &actions::ToggleFocus,
18015        window: &mut Window,
18016        cx: &mut Context<Workspace>,
18017    ) {
18018        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18019            return;
18020        };
18021        workspace.activate_item(&item, true, true, window, cx);
18022    }
18023
18024    pub fn toggle_fold(
18025        &mut self,
18026        _: &actions::ToggleFold,
18027        window: &mut Window,
18028        cx: &mut Context<Self>,
18029    ) {
18030        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18031            let selection = self.selections.newest::<Point>(cx);
18032
18033            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18034            let range = if selection.is_empty() {
18035                let point = selection.head().to_display_point(&display_map);
18036                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18037                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18038                    .to_point(&display_map);
18039                start..end
18040            } else {
18041                selection.range()
18042            };
18043            if display_map.folds_in_range(range).next().is_some() {
18044                self.unfold_lines(&Default::default(), window, cx)
18045            } else {
18046                self.fold(&Default::default(), window, cx)
18047            }
18048        } else {
18049            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18050            let buffer_ids: HashSet<_> = self
18051                .selections
18052                .disjoint_anchor_ranges()
18053                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18054                .collect();
18055
18056            let should_unfold = buffer_ids
18057                .iter()
18058                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18059
18060            for buffer_id in buffer_ids {
18061                if should_unfold {
18062                    self.unfold_buffer(buffer_id, cx);
18063                } else {
18064                    self.fold_buffer(buffer_id, cx);
18065                }
18066            }
18067        }
18068    }
18069
18070    pub fn toggle_fold_recursive(
18071        &mut self,
18072        _: &actions::ToggleFoldRecursive,
18073        window: &mut Window,
18074        cx: &mut Context<Self>,
18075    ) {
18076        let selection = self.selections.newest::<Point>(cx);
18077
18078        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18079        let range = if selection.is_empty() {
18080            let point = selection.head().to_display_point(&display_map);
18081            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18082            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18083                .to_point(&display_map);
18084            start..end
18085        } else {
18086            selection.range()
18087        };
18088        if display_map.folds_in_range(range).next().is_some() {
18089            self.unfold_recursive(&Default::default(), window, cx)
18090        } else {
18091            self.fold_recursive(&Default::default(), window, cx)
18092        }
18093    }
18094
18095    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18096        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18097            let mut to_fold = Vec::new();
18098            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18099            let selections = self.selections.all_adjusted(cx);
18100
18101            for selection in selections {
18102                let range = selection.range().sorted();
18103                let buffer_start_row = range.start.row;
18104
18105                if range.start.row != range.end.row {
18106                    let mut found = false;
18107                    let mut row = range.start.row;
18108                    while row <= range.end.row {
18109                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18110                        {
18111                            found = true;
18112                            row = crease.range().end.row + 1;
18113                            to_fold.push(crease);
18114                        } else {
18115                            row += 1
18116                        }
18117                    }
18118                    if found {
18119                        continue;
18120                    }
18121                }
18122
18123                for row in (0..=range.start.row).rev() {
18124                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18125                        && crease.range().end.row >= buffer_start_row
18126                    {
18127                        to_fold.push(crease);
18128                        if row <= range.start.row {
18129                            break;
18130                        }
18131                    }
18132                }
18133            }
18134
18135            self.fold_creases(to_fold, true, window, cx);
18136        } else {
18137            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18138            let buffer_ids = self
18139                .selections
18140                .disjoint_anchor_ranges()
18141                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18142                .collect::<HashSet<_>>();
18143            for buffer_id in buffer_ids {
18144                self.fold_buffer(buffer_id, cx);
18145            }
18146        }
18147    }
18148
18149    pub fn toggle_fold_all(
18150        &mut self,
18151        _: &actions::ToggleFoldAll,
18152        window: &mut Window,
18153        cx: &mut Context<Self>,
18154    ) {
18155        if self.buffer.read(cx).is_singleton() {
18156            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18157            let has_folds = display_map
18158                .folds_in_range(0..display_map.buffer_snapshot().len())
18159                .next()
18160                .is_some();
18161
18162            if has_folds {
18163                self.unfold_all(&actions::UnfoldAll, window, cx);
18164            } else {
18165                self.fold_all(&actions::FoldAll, window, cx);
18166            }
18167        } else {
18168            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18169            let should_unfold = buffer_ids
18170                .iter()
18171                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18172
18173            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18174                editor
18175                    .update_in(cx, |editor, _, cx| {
18176                        for buffer_id in buffer_ids {
18177                            if should_unfold {
18178                                editor.unfold_buffer(buffer_id, cx);
18179                            } else {
18180                                editor.fold_buffer(buffer_id, cx);
18181                            }
18182                        }
18183                    })
18184                    .ok();
18185            });
18186        }
18187    }
18188
18189    fn fold_at_level(
18190        &mut self,
18191        fold_at: &FoldAtLevel,
18192        window: &mut Window,
18193        cx: &mut Context<Self>,
18194    ) {
18195        if !self.buffer.read(cx).is_singleton() {
18196            return;
18197        }
18198
18199        let fold_at_level = fold_at.0;
18200        let snapshot = self.buffer.read(cx).snapshot(cx);
18201        let mut to_fold = Vec::new();
18202        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18203
18204        let row_ranges_to_keep: Vec<Range<u32>> = self
18205            .selections
18206            .all::<Point>(cx)
18207            .into_iter()
18208            .map(|sel| sel.start.row..sel.end.row)
18209            .collect();
18210
18211        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18212            while start_row < end_row {
18213                match self
18214                    .snapshot(window, cx)
18215                    .crease_for_buffer_row(MultiBufferRow(start_row))
18216                {
18217                    Some(crease) => {
18218                        let nested_start_row = crease.range().start.row + 1;
18219                        let nested_end_row = crease.range().end.row;
18220
18221                        if current_level < fold_at_level {
18222                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18223                        } else if current_level == fold_at_level {
18224                            // Fold iff there is no selection completely contained within the fold region
18225                            if !row_ranges_to_keep.iter().any(|selection| {
18226                                selection.end >= nested_start_row
18227                                    && selection.start <= nested_end_row
18228                            }) {
18229                                to_fold.push(crease);
18230                            }
18231                        }
18232
18233                        start_row = nested_end_row + 1;
18234                    }
18235                    None => start_row += 1,
18236                }
18237            }
18238        }
18239
18240        self.fold_creases(to_fold, true, window, cx);
18241    }
18242
18243    pub fn fold_at_level_1(
18244        &mut self,
18245        _: &actions::FoldAtLevel1,
18246        window: &mut Window,
18247        cx: &mut Context<Self>,
18248    ) {
18249        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18250    }
18251
18252    pub fn fold_at_level_2(
18253        &mut self,
18254        _: &actions::FoldAtLevel2,
18255        window: &mut Window,
18256        cx: &mut Context<Self>,
18257    ) {
18258        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18259    }
18260
18261    pub fn fold_at_level_3(
18262        &mut self,
18263        _: &actions::FoldAtLevel3,
18264        window: &mut Window,
18265        cx: &mut Context<Self>,
18266    ) {
18267        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18268    }
18269
18270    pub fn fold_at_level_4(
18271        &mut self,
18272        _: &actions::FoldAtLevel4,
18273        window: &mut Window,
18274        cx: &mut Context<Self>,
18275    ) {
18276        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18277    }
18278
18279    pub fn fold_at_level_5(
18280        &mut self,
18281        _: &actions::FoldAtLevel5,
18282        window: &mut Window,
18283        cx: &mut Context<Self>,
18284    ) {
18285        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18286    }
18287
18288    pub fn fold_at_level_6(
18289        &mut self,
18290        _: &actions::FoldAtLevel6,
18291        window: &mut Window,
18292        cx: &mut Context<Self>,
18293    ) {
18294        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18295    }
18296
18297    pub fn fold_at_level_7(
18298        &mut self,
18299        _: &actions::FoldAtLevel7,
18300        window: &mut Window,
18301        cx: &mut Context<Self>,
18302    ) {
18303        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18304    }
18305
18306    pub fn fold_at_level_8(
18307        &mut self,
18308        _: &actions::FoldAtLevel8,
18309        window: &mut Window,
18310        cx: &mut Context<Self>,
18311    ) {
18312        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18313    }
18314
18315    pub fn fold_at_level_9(
18316        &mut self,
18317        _: &actions::FoldAtLevel9,
18318        window: &mut Window,
18319        cx: &mut Context<Self>,
18320    ) {
18321        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18322    }
18323
18324    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18325        if self.buffer.read(cx).is_singleton() {
18326            let mut fold_ranges = Vec::new();
18327            let snapshot = self.buffer.read(cx).snapshot(cx);
18328
18329            for row in 0..snapshot.max_row().0 {
18330                if let Some(foldable_range) = self
18331                    .snapshot(window, cx)
18332                    .crease_for_buffer_row(MultiBufferRow(row))
18333                {
18334                    fold_ranges.push(foldable_range);
18335                }
18336            }
18337
18338            self.fold_creases(fold_ranges, true, window, cx);
18339        } else {
18340            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18341                editor
18342                    .update_in(cx, |editor, _, cx| {
18343                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18344                            editor.fold_buffer(buffer_id, cx);
18345                        }
18346                    })
18347                    .ok();
18348            });
18349        }
18350    }
18351
18352    pub fn fold_function_bodies(
18353        &mut self,
18354        _: &actions::FoldFunctionBodies,
18355        window: &mut Window,
18356        cx: &mut Context<Self>,
18357    ) {
18358        let snapshot = self.buffer.read(cx).snapshot(cx);
18359
18360        let ranges = snapshot
18361            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18362            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18363            .collect::<Vec<_>>();
18364
18365        let creases = ranges
18366            .into_iter()
18367            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18368            .collect();
18369
18370        self.fold_creases(creases, true, window, cx);
18371    }
18372
18373    pub fn fold_recursive(
18374        &mut self,
18375        _: &actions::FoldRecursive,
18376        window: &mut Window,
18377        cx: &mut Context<Self>,
18378    ) {
18379        let mut to_fold = Vec::new();
18380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18381        let selections = self.selections.all_adjusted(cx);
18382
18383        for selection in selections {
18384            let range = selection.range().sorted();
18385            let buffer_start_row = range.start.row;
18386
18387            if range.start.row != range.end.row {
18388                let mut found = false;
18389                for row in range.start.row..=range.end.row {
18390                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18391                        found = true;
18392                        to_fold.push(crease);
18393                    }
18394                }
18395                if found {
18396                    continue;
18397                }
18398            }
18399
18400            for row in (0..=range.start.row).rev() {
18401                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18402                    if crease.range().end.row >= buffer_start_row {
18403                        to_fold.push(crease);
18404                    } else {
18405                        break;
18406                    }
18407                }
18408            }
18409        }
18410
18411        self.fold_creases(to_fold, true, window, cx);
18412    }
18413
18414    pub fn fold_at(
18415        &mut self,
18416        buffer_row: MultiBufferRow,
18417        window: &mut Window,
18418        cx: &mut Context<Self>,
18419    ) {
18420        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18421
18422        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18423            let autoscroll = self
18424                .selections
18425                .all::<Point>(cx)
18426                .iter()
18427                .any(|selection| crease.range().overlaps(&selection.range()));
18428
18429            self.fold_creases(vec![crease], autoscroll, window, cx);
18430        }
18431    }
18432
18433    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18434        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18435            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18436            let buffer = display_map.buffer_snapshot();
18437            let selections = self.selections.all::<Point>(cx);
18438            let ranges = selections
18439                .iter()
18440                .map(|s| {
18441                    let range = s.display_range(&display_map).sorted();
18442                    let mut start = range.start.to_point(&display_map);
18443                    let mut end = range.end.to_point(&display_map);
18444                    start.column = 0;
18445                    end.column = buffer.line_len(MultiBufferRow(end.row));
18446                    start..end
18447                })
18448                .collect::<Vec<_>>();
18449
18450            self.unfold_ranges(&ranges, true, true, cx);
18451        } else {
18452            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18453            let buffer_ids = self
18454                .selections
18455                .disjoint_anchor_ranges()
18456                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18457                .collect::<HashSet<_>>();
18458            for buffer_id in buffer_ids {
18459                self.unfold_buffer(buffer_id, cx);
18460            }
18461        }
18462    }
18463
18464    pub fn unfold_recursive(
18465        &mut self,
18466        _: &UnfoldRecursive,
18467        _window: &mut Window,
18468        cx: &mut Context<Self>,
18469    ) {
18470        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18471        let selections = self.selections.all::<Point>(cx);
18472        let ranges = selections
18473            .iter()
18474            .map(|s| {
18475                let mut range = s.display_range(&display_map).sorted();
18476                *range.start.column_mut() = 0;
18477                *range.end.column_mut() = display_map.line_len(range.end.row());
18478                let start = range.start.to_point(&display_map);
18479                let end = range.end.to_point(&display_map);
18480                start..end
18481            })
18482            .collect::<Vec<_>>();
18483
18484        self.unfold_ranges(&ranges, true, true, cx);
18485    }
18486
18487    pub fn unfold_at(
18488        &mut self,
18489        buffer_row: MultiBufferRow,
18490        _window: &mut Window,
18491        cx: &mut Context<Self>,
18492    ) {
18493        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18494
18495        let intersection_range = Point::new(buffer_row.0, 0)
18496            ..Point::new(
18497                buffer_row.0,
18498                display_map.buffer_snapshot().line_len(buffer_row),
18499            );
18500
18501        let autoscroll = self
18502            .selections
18503            .all::<Point>(cx)
18504            .iter()
18505            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18506
18507        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18508    }
18509
18510    pub fn unfold_all(
18511        &mut self,
18512        _: &actions::UnfoldAll,
18513        _window: &mut Window,
18514        cx: &mut Context<Self>,
18515    ) {
18516        if self.buffer.read(cx).is_singleton() {
18517            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18518            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18519        } else {
18520            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18521                editor
18522                    .update(cx, |editor, cx| {
18523                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18524                            editor.unfold_buffer(buffer_id, cx);
18525                        }
18526                    })
18527                    .ok();
18528            });
18529        }
18530    }
18531
18532    pub fn fold_selected_ranges(
18533        &mut self,
18534        _: &FoldSelectedRanges,
18535        window: &mut Window,
18536        cx: &mut Context<Self>,
18537    ) {
18538        let selections = self.selections.all_adjusted(cx);
18539        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18540        let ranges = selections
18541            .into_iter()
18542            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18543            .collect::<Vec<_>>();
18544        self.fold_creases(ranges, true, window, cx);
18545    }
18546
18547    pub fn fold_ranges<T: ToOffset + Clone>(
18548        &mut self,
18549        ranges: Vec<Range<T>>,
18550        auto_scroll: bool,
18551        window: &mut Window,
18552        cx: &mut Context<Self>,
18553    ) {
18554        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18555        let ranges = ranges
18556            .into_iter()
18557            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18558            .collect::<Vec<_>>();
18559        self.fold_creases(ranges, auto_scroll, window, cx);
18560    }
18561
18562    pub fn fold_creases<T: ToOffset + Clone>(
18563        &mut self,
18564        creases: Vec<Crease<T>>,
18565        auto_scroll: bool,
18566        _window: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) {
18569        if creases.is_empty() {
18570            return;
18571        }
18572
18573        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18574
18575        if auto_scroll {
18576            self.request_autoscroll(Autoscroll::fit(), cx);
18577        }
18578
18579        cx.notify();
18580
18581        self.scrollbar_marker_state.dirty = true;
18582        self.folds_did_change(cx);
18583    }
18584
18585    /// Removes any folds whose ranges intersect any of the given ranges.
18586    pub fn unfold_ranges<T: ToOffset + Clone>(
18587        &mut self,
18588        ranges: &[Range<T>],
18589        inclusive: bool,
18590        auto_scroll: bool,
18591        cx: &mut Context<Self>,
18592    ) {
18593        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18594            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18595        });
18596        self.folds_did_change(cx);
18597    }
18598
18599    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18600        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18601            return;
18602        }
18603        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18604        self.display_map.update(cx, |display_map, cx| {
18605            display_map.fold_buffers([buffer_id], cx)
18606        });
18607        cx.emit(EditorEvent::BufferFoldToggled {
18608            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18609            folded: true,
18610        });
18611        cx.notify();
18612    }
18613
18614    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18615        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18616            return;
18617        }
18618        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18619        self.display_map.update(cx, |display_map, cx| {
18620            display_map.unfold_buffers([buffer_id], cx);
18621        });
18622        cx.emit(EditorEvent::BufferFoldToggled {
18623            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18624            folded: false,
18625        });
18626        cx.notify();
18627    }
18628
18629    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18630        self.display_map.read(cx).is_buffer_folded(buffer)
18631    }
18632
18633    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18634        self.display_map.read(cx).folded_buffers()
18635    }
18636
18637    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18638        self.display_map.update(cx, |display_map, cx| {
18639            display_map.disable_header_for_buffer(buffer_id, cx);
18640        });
18641        cx.notify();
18642    }
18643
18644    /// Removes any folds with the given ranges.
18645    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18646        &mut self,
18647        ranges: &[Range<T>],
18648        type_id: TypeId,
18649        auto_scroll: bool,
18650        cx: &mut Context<Self>,
18651    ) {
18652        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18653            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18654        });
18655        self.folds_did_change(cx);
18656    }
18657
18658    fn remove_folds_with<T: ToOffset + Clone>(
18659        &mut self,
18660        ranges: &[Range<T>],
18661        auto_scroll: bool,
18662        cx: &mut Context<Self>,
18663        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18664    ) {
18665        if ranges.is_empty() {
18666            return;
18667        }
18668
18669        let mut buffers_affected = HashSet::default();
18670        let multi_buffer = self.buffer().read(cx);
18671        for range in ranges {
18672            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18673                buffers_affected.insert(buffer.read(cx).remote_id());
18674            };
18675        }
18676
18677        self.display_map.update(cx, update);
18678
18679        if auto_scroll {
18680            self.request_autoscroll(Autoscroll::fit(), cx);
18681        }
18682
18683        cx.notify();
18684        self.scrollbar_marker_state.dirty = true;
18685        self.active_indent_guides_state.dirty = true;
18686    }
18687
18688    pub fn update_renderer_widths(
18689        &mut self,
18690        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18691        cx: &mut Context<Self>,
18692    ) -> bool {
18693        self.display_map
18694            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18695    }
18696
18697    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18698        self.display_map.read(cx).fold_placeholder.clone()
18699    }
18700
18701    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18702        self.buffer.update(cx, |buffer, cx| {
18703            buffer.set_all_diff_hunks_expanded(cx);
18704        });
18705    }
18706
18707    pub fn expand_all_diff_hunks(
18708        &mut self,
18709        _: &ExpandAllDiffHunks,
18710        _window: &mut Window,
18711        cx: &mut Context<Self>,
18712    ) {
18713        self.buffer.update(cx, |buffer, cx| {
18714            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18715        });
18716    }
18717
18718    pub fn toggle_selected_diff_hunks(
18719        &mut self,
18720        _: &ToggleSelectedDiffHunks,
18721        _window: &mut Window,
18722        cx: &mut Context<Self>,
18723    ) {
18724        let ranges: Vec<_> = self
18725            .selections
18726            .disjoint_anchors()
18727            .iter()
18728            .map(|s| s.range())
18729            .collect();
18730        self.toggle_diff_hunks_in_ranges(ranges, cx);
18731    }
18732
18733    pub fn diff_hunks_in_ranges<'a>(
18734        &'a self,
18735        ranges: &'a [Range<Anchor>],
18736        buffer: &'a MultiBufferSnapshot,
18737    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18738        ranges.iter().flat_map(move |range| {
18739            let end_excerpt_id = range.end.excerpt_id;
18740            let range = range.to_point(buffer);
18741            let mut peek_end = range.end;
18742            if range.end.row < buffer.max_row().0 {
18743                peek_end = Point::new(range.end.row + 1, 0);
18744            }
18745            buffer
18746                .diff_hunks_in_range(range.start..peek_end)
18747                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18748        })
18749    }
18750
18751    pub fn has_stageable_diff_hunks_in_ranges(
18752        &self,
18753        ranges: &[Range<Anchor>],
18754        snapshot: &MultiBufferSnapshot,
18755    ) -> bool {
18756        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18757        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18758    }
18759
18760    pub fn toggle_staged_selected_diff_hunks(
18761        &mut self,
18762        _: &::git::ToggleStaged,
18763        _: &mut Window,
18764        cx: &mut Context<Self>,
18765    ) {
18766        let snapshot = self.buffer.read(cx).snapshot(cx);
18767        let ranges: Vec<_> = self
18768            .selections
18769            .disjoint_anchors()
18770            .iter()
18771            .map(|s| s.range())
18772            .collect();
18773        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18774        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18775    }
18776
18777    pub fn set_render_diff_hunk_controls(
18778        &mut self,
18779        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18780        cx: &mut Context<Self>,
18781    ) {
18782        self.render_diff_hunk_controls = render_diff_hunk_controls;
18783        cx.notify();
18784    }
18785
18786    pub fn stage_and_next(
18787        &mut self,
18788        _: &::git::StageAndNext,
18789        window: &mut Window,
18790        cx: &mut Context<Self>,
18791    ) {
18792        self.do_stage_or_unstage_and_next(true, window, cx);
18793    }
18794
18795    pub fn unstage_and_next(
18796        &mut self,
18797        _: &::git::UnstageAndNext,
18798        window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        self.do_stage_or_unstage_and_next(false, window, cx);
18802    }
18803
18804    pub fn stage_or_unstage_diff_hunks(
18805        &mut self,
18806        stage: bool,
18807        ranges: Vec<Range<Anchor>>,
18808        cx: &mut Context<Self>,
18809    ) {
18810        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18811        cx.spawn(async move |this, cx| {
18812            task.await?;
18813            this.update(cx, |this, cx| {
18814                let snapshot = this.buffer.read(cx).snapshot(cx);
18815                let chunk_by = this
18816                    .diff_hunks_in_ranges(&ranges, &snapshot)
18817                    .chunk_by(|hunk| hunk.buffer_id);
18818                for (buffer_id, hunks) in &chunk_by {
18819                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18820                }
18821            })
18822        })
18823        .detach_and_log_err(cx);
18824    }
18825
18826    fn save_buffers_for_ranges_if_needed(
18827        &mut self,
18828        ranges: &[Range<Anchor>],
18829        cx: &mut Context<Editor>,
18830    ) -> Task<Result<()>> {
18831        let multibuffer = self.buffer.read(cx);
18832        let snapshot = multibuffer.read(cx);
18833        let buffer_ids: HashSet<_> = ranges
18834            .iter()
18835            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18836            .collect();
18837        drop(snapshot);
18838
18839        let mut buffers = HashSet::default();
18840        for buffer_id in buffer_ids {
18841            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18842                let buffer = buffer_entity.read(cx);
18843                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18844                {
18845                    buffers.insert(buffer_entity);
18846                }
18847            }
18848        }
18849
18850        if let Some(project) = &self.project {
18851            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18852        } else {
18853            Task::ready(Ok(()))
18854        }
18855    }
18856
18857    fn do_stage_or_unstage_and_next(
18858        &mut self,
18859        stage: bool,
18860        window: &mut Window,
18861        cx: &mut Context<Self>,
18862    ) {
18863        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18864
18865        if ranges.iter().any(|range| range.start != range.end) {
18866            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18867            return;
18868        }
18869
18870        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18871        let snapshot = self.snapshot(window, cx);
18872        let position = self.selections.newest::<Point>(cx).head();
18873        let mut row = snapshot
18874            .buffer_snapshot()
18875            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18876            .find(|hunk| hunk.row_range.start.0 > position.row)
18877            .map(|hunk| hunk.row_range.start);
18878
18879        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18880        // Outside of the project diff editor, wrap around to the beginning.
18881        if !all_diff_hunks_expanded {
18882            row = row.or_else(|| {
18883                snapshot
18884                    .buffer_snapshot()
18885                    .diff_hunks_in_range(Point::zero()..position)
18886                    .find(|hunk| hunk.row_range.end.0 < position.row)
18887                    .map(|hunk| hunk.row_range.start)
18888            });
18889        }
18890
18891        if let Some(row) = row {
18892            let destination = Point::new(row.0, 0);
18893            let autoscroll = Autoscroll::center();
18894
18895            self.unfold_ranges(&[destination..destination], false, false, cx);
18896            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18897                s.select_ranges([destination..destination]);
18898            });
18899        }
18900    }
18901
18902    fn do_stage_or_unstage(
18903        &self,
18904        stage: bool,
18905        buffer_id: BufferId,
18906        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18907        cx: &mut App,
18908    ) -> Option<()> {
18909        let project = self.project()?;
18910        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18911        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18912        let buffer_snapshot = buffer.read(cx).snapshot();
18913        let file_exists = buffer_snapshot
18914            .file()
18915            .is_some_and(|file| file.disk_state().exists());
18916        diff.update(cx, |diff, cx| {
18917            diff.stage_or_unstage_hunks(
18918                stage,
18919                &hunks
18920                    .map(|hunk| buffer_diff::DiffHunk {
18921                        buffer_range: hunk.buffer_range,
18922                        diff_base_byte_range: hunk.diff_base_byte_range,
18923                        secondary_status: hunk.secondary_status,
18924                        range: Point::zero()..Point::zero(), // unused
18925                    })
18926                    .collect::<Vec<_>>(),
18927                &buffer_snapshot,
18928                file_exists,
18929                cx,
18930            )
18931        });
18932        None
18933    }
18934
18935    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18936        let ranges: Vec<_> = self
18937            .selections
18938            .disjoint_anchors()
18939            .iter()
18940            .map(|s| s.range())
18941            .collect();
18942        self.buffer
18943            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18944    }
18945
18946    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18947        self.buffer.update(cx, |buffer, cx| {
18948            let ranges = vec![Anchor::min()..Anchor::max()];
18949            if !buffer.all_diff_hunks_expanded()
18950                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18951            {
18952                buffer.collapse_diff_hunks(ranges, cx);
18953                true
18954            } else {
18955                false
18956            }
18957        })
18958    }
18959
18960    fn toggle_diff_hunks_in_ranges(
18961        &mut self,
18962        ranges: Vec<Range<Anchor>>,
18963        cx: &mut Context<Editor>,
18964    ) {
18965        self.buffer.update(cx, |buffer, cx| {
18966            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18967            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18968        })
18969    }
18970
18971    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18972        self.buffer.update(cx, |buffer, cx| {
18973            let snapshot = buffer.snapshot(cx);
18974            let excerpt_id = range.end.excerpt_id;
18975            let point_range = range.to_point(&snapshot);
18976            let expand = !buffer.single_hunk_is_expanded(range, cx);
18977            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18978        })
18979    }
18980
18981    pub(crate) fn apply_all_diff_hunks(
18982        &mut self,
18983        _: &ApplyAllDiffHunks,
18984        window: &mut Window,
18985        cx: &mut Context<Self>,
18986    ) {
18987        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18988
18989        let buffers = self.buffer.read(cx).all_buffers();
18990        for branch_buffer in buffers {
18991            branch_buffer.update(cx, |branch_buffer, cx| {
18992                branch_buffer.merge_into_base(Vec::new(), cx);
18993            });
18994        }
18995
18996        if let Some(project) = self.project.clone() {
18997            self.save(
18998                SaveOptions {
18999                    format: true,
19000                    autosave: false,
19001                },
19002                project,
19003                window,
19004                cx,
19005            )
19006            .detach_and_log_err(cx);
19007        }
19008    }
19009
19010    pub(crate) fn apply_selected_diff_hunks(
19011        &mut self,
19012        _: &ApplyDiffHunk,
19013        window: &mut Window,
19014        cx: &mut Context<Self>,
19015    ) {
19016        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19017        let snapshot = self.snapshot(window, cx);
19018        let hunks = snapshot.hunks_for_ranges(
19019            self.selections
19020                .all(cx)
19021                .into_iter()
19022                .map(|selection| selection.range()),
19023        );
19024        let mut ranges_by_buffer = HashMap::default();
19025        self.transact(window, cx, |editor, _window, cx| {
19026            for hunk in hunks {
19027                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19028                    ranges_by_buffer
19029                        .entry(buffer.clone())
19030                        .or_insert_with(Vec::new)
19031                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19032                }
19033            }
19034
19035            for (buffer, ranges) in ranges_by_buffer {
19036                buffer.update(cx, |buffer, cx| {
19037                    buffer.merge_into_base(ranges, cx);
19038                });
19039            }
19040        });
19041
19042        if let Some(project) = self.project.clone() {
19043            self.save(
19044                SaveOptions {
19045                    format: true,
19046                    autosave: false,
19047                },
19048                project,
19049                window,
19050                cx,
19051            )
19052            .detach_and_log_err(cx);
19053        }
19054    }
19055
19056    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19057        if hovered != self.gutter_hovered {
19058            self.gutter_hovered = hovered;
19059            cx.notify();
19060        }
19061    }
19062
19063    pub fn insert_blocks(
19064        &mut self,
19065        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19066        autoscroll: Option<Autoscroll>,
19067        cx: &mut Context<Self>,
19068    ) -> Vec<CustomBlockId> {
19069        let blocks = self
19070            .display_map
19071            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19072        if let Some(autoscroll) = autoscroll {
19073            self.request_autoscroll(autoscroll, cx);
19074        }
19075        cx.notify();
19076        blocks
19077    }
19078
19079    pub fn resize_blocks(
19080        &mut self,
19081        heights: HashMap<CustomBlockId, u32>,
19082        autoscroll: Option<Autoscroll>,
19083        cx: &mut Context<Self>,
19084    ) {
19085        self.display_map
19086            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19087        if let Some(autoscroll) = autoscroll {
19088            self.request_autoscroll(autoscroll, cx);
19089        }
19090        cx.notify();
19091    }
19092
19093    pub fn replace_blocks(
19094        &mut self,
19095        renderers: HashMap<CustomBlockId, RenderBlock>,
19096        autoscroll: Option<Autoscroll>,
19097        cx: &mut Context<Self>,
19098    ) {
19099        self.display_map
19100            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19101        if let Some(autoscroll) = autoscroll {
19102            self.request_autoscroll(autoscroll, cx);
19103        }
19104        cx.notify();
19105    }
19106
19107    pub fn remove_blocks(
19108        &mut self,
19109        block_ids: HashSet<CustomBlockId>,
19110        autoscroll: Option<Autoscroll>,
19111        cx: &mut Context<Self>,
19112    ) {
19113        self.display_map.update(cx, |display_map, cx| {
19114            display_map.remove_blocks(block_ids, cx)
19115        });
19116        if let Some(autoscroll) = autoscroll {
19117            self.request_autoscroll(autoscroll, cx);
19118        }
19119        cx.notify();
19120    }
19121
19122    pub fn row_for_block(
19123        &self,
19124        block_id: CustomBlockId,
19125        cx: &mut Context<Self>,
19126    ) -> Option<DisplayRow> {
19127        self.display_map
19128            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19129    }
19130
19131    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19132        self.focused_block = Some(focused_block);
19133    }
19134
19135    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19136        self.focused_block.take()
19137    }
19138
19139    pub fn insert_creases(
19140        &mut self,
19141        creases: impl IntoIterator<Item = Crease<Anchor>>,
19142        cx: &mut Context<Self>,
19143    ) -> Vec<CreaseId> {
19144        self.display_map
19145            .update(cx, |map, cx| map.insert_creases(creases, cx))
19146    }
19147
19148    pub fn remove_creases(
19149        &mut self,
19150        ids: impl IntoIterator<Item = CreaseId>,
19151        cx: &mut Context<Self>,
19152    ) -> Vec<(CreaseId, Range<Anchor>)> {
19153        self.display_map
19154            .update(cx, |map, cx| map.remove_creases(ids, cx))
19155    }
19156
19157    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19158        self.display_map
19159            .update(cx, |map, cx| map.snapshot(cx))
19160            .longest_row()
19161    }
19162
19163    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19164        self.display_map
19165            .update(cx, |map, cx| map.snapshot(cx))
19166            .max_point()
19167    }
19168
19169    pub fn text(&self, cx: &App) -> String {
19170        self.buffer.read(cx).read(cx).text()
19171    }
19172
19173    pub fn is_empty(&self, cx: &App) -> bool {
19174        self.buffer.read(cx).read(cx).is_empty()
19175    }
19176
19177    pub fn text_option(&self, cx: &App) -> Option<String> {
19178        let text = self.text(cx);
19179        let text = text.trim();
19180
19181        if text.is_empty() {
19182            return None;
19183        }
19184
19185        Some(text.to_string())
19186    }
19187
19188    pub fn set_text(
19189        &mut self,
19190        text: impl Into<Arc<str>>,
19191        window: &mut Window,
19192        cx: &mut Context<Self>,
19193    ) {
19194        self.transact(window, cx, |this, _, cx| {
19195            this.buffer
19196                .read(cx)
19197                .as_singleton()
19198                .expect("you can only call set_text on editors for singleton buffers")
19199                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19200        });
19201    }
19202
19203    pub fn display_text(&self, cx: &mut App) -> String {
19204        self.display_map
19205            .update(cx, |map, cx| map.snapshot(cx))
19206            .text()
19207    }
19208
19209    fn create_minimap(
19210        &self,
19211        minimap_settings: MinimapSettings,
19212        window: &mut Window,
19213        cx: &mut Context<Self>,
19214    ) -> Option<Entity<Self>> {
19215        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19216            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19217    }
19218
19219    fn initialize_new_minimap(
19220        &self,
19221        minimap_settings: MinimapSettings,
19222        window: &mut Window,
19223        cx: &mut Context<Self>,
19224    ) -> Entity<Self> {
19225        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19226
19227        let mut minimap = Editor::new_internal(
19228            EditorMode::Minimap {
19229                parent: cx.weak_entity(),
19230            },
19231            self.buffer.clone(),
19232            None,
19233            Some(self.display_map.clone()),
19234            window,
19235            cx,
19236        );
19237        minimap.scroll_manager.clone_state(&self.scroll_manager);
19238        minimap.set_text_style_refinement(TextStyleRefinement {
19239            font_size: Some(MINIMAP_FONT_SIZE),
19240            font_weight: Some(MINIMAP_FONT_WEIGHT),
19241            ..Default::default()
19242        });
19243        minimap.update_minimap_configuration(minimap_settings, cx);
19244        cx.new(|_| minimap)
19245    }
19246
19247    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19248        let current_line_highlight = minimap_settings
19249            .current_line_highlight
19250            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19251        self.set_current_line_highlight(Some(current_line_highlight));
19252    }
19253
19254    pub fn minimap(&self) -> Option<&Entity<Self>> {
19255        self.minimap
19256            .as_ref()
19257            .filter(|_| self.minimap_visibility.visible())
19258    }
19259
19260    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19261        let mut wrap_guides = smallvec![];
19262
19263        if self.show_wrap_guides == Some(false) {
19264            return wrap_guides;
19265        }
19266
19267        let settings = self.buffer.read(cx).language_settings(cx);
19268        if settings.show_wrap_guides {
19269            match self.soft_wrap_mode(cx) {
19270                SoftWrap::Column(soft_wrap) => {
19271                    wrap_guides.push((soft_wrap as usize, true));
19272                }
19273                SoftWrap::Bounded(soft_wrap) => {
19274                    wrap_guides.push((soft_wrap as usize, true));
19275                }
19276                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19277            }
19278            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19279        }
19280
19281        wrap_guides
19282    }
19283
19284    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19285        let settings = self.buffer.read(cx).language_settings(cx);
19286        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19287        match mode {
19288            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19289                SoftWrap::None
19290            }
19291            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19292            language_settings::SoftWrap::PreferredLineLength => {
19293                SoftWrap::Column(settings.preferred_line_length)
19294            }
19295            language_settings::SoftWrap::Bounded => {
19296                SoftWrap::Bounded(settings.preferred_line_length)
19297            }
19298        }
19299    }
19300
19301    pub fn set_soft_wrap_mode(
19302        &mut self,
19303        mode: language_settings::SoftWrap,
19304
19305        cx: &mut Context<Self>,
19306    ) {
19307        self.soft_wrap_mode_override = Some(mode);
19308        cx.notify();
19309    }
19310
19311    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19312        self.hard_wrap = hard_wrap;
19313        cx.notify();
19314    }
19315
19316    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19317        self.text_style_refinement = Some(style);
19318    }
19319
19320    /// called by the Element so we know what style we were most recently rendered with.
19321    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19322        // We intentionally do not inform the display map about the minimap style
19323        // so that wrapping is not recalculated and stays consistent for the editor
19324        // and its linked minimap.
19325        if !self.mode.is_minimap() {
19326            let font = style.text.font();
19327            let font_size = style.text.font_size.to_pixels(window.rem_size());
19328            let display_map = self
19329                .placeholder_display_map
19330                .as_ref()
19331                .filter(|_| self.is_empty(cx))
19332                .unwrap_or(&self.display_map);
19333
19334            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19335        }
19336        self.style = Some(style);
19337    }
19338
19339    pub fn style(&self) -> Option<&EditorStyle> {
19340        self.style.as_ref()
19341    }
19342
19343    // Called by the element. This method is not designed to be called outside of the editor
19344    // element's layout code because it does not notify when rewrapping is computed synchronously.
19345    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19346        if self.is_empty(cx) {
19347            self.placeholder_display_map
19348                .as_ref()
19349                .map_or(false, |display_map| {
19350                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19351                })
19352        } else {
19353            self.display_map
19354                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19355        }
19356    }
19357
19358    pub fn set_soft_wrap(&mut self) {
19359        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19360    }
19361
19362    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19363        if self.soft_wrap_mode_override.is_some() {
19364            self.soft_wrap_mode_override.take();
19365        } else {
19366            let soft_wrap = match self.soft_wrap_mode(cx) {
19367                SoftWrap::GitDiff => return,
19368                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19369                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19370                    language_settings::SoftWrap::None
19371                }
19372            };
19373            self.soft_wrap_mode_override = Some(soft_wrap);
19374        }
19375        cx.notify();
19376    }
19377
19378    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19379        let Some(workspace) = self.workspace() else {
19380            return;
19381        };
19382        let fs = workspace.read(cx).app_state().fs.clone();
19383        let current_show = TabBarSettings::get_global(cx).show;
19384        update_settings_file(fs, cx, move |setting, _| {
19385            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19386        });
19387    }
19388
19389    pub fn toggle_indent_guides(
19390        &mut self,
19391        _: &ToggleIndentGuides,
19392        _: &mut Window,
19393        cx: &mut Context<Self>,
19394    ) {
19395        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19396            self.buffer
19397                .read(cx)
19398                .language_settings(cx)
19399                .indent_guides
19400                .enabled
19401        });
19402        self.show_indent_guides = Some(!currently_enabled);
19403        cx.notify();
19404    }
19405
19406    fn should_show_indent_guides(&self) -> Option<bool> {
19407        self.show_indent_guides
19408    }
19409
19410    pub fn toggle_line_numbers(
19411        &mut self,
19412        _: &ToggleLineNumbers,
19413        _: &mut Window,
19414        cx: &mut Context<Self>,
19415    ) {
19416        let mut editor_settings = EditorSettings::get_global(cx).clone();
19417        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19418        EditorSettings::override_global(editor_settings, cx);
19419    }
19420
19421    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19422        if let Some(show_line_numbers) = self.show_line_numbers {
19423            return show_line_numbers;
19424        }
19425        EditorSettings::get_global(cx).gutter.line_numbers
19426    }
19427
19428    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19429        self.use_relative_line_numbers
19430            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19431    }
19432
19433    pub fn toggle_relative_line_numbers(
19434        &mut self,
19435        _: &ToggleRelativeLineNumbers,
19436        _: &mut Window,
19437        cx: &mut Context<Self>,
19438    ) {
19439        let is_relative = self.should_use_relative_line_numbers(cx);
19440        self.set_relative_line_number(Some(!is_relative), cx)
19441    }
19442
19443    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19444        self.use_relative_line_numbers = is_relative;
19445        cx.notify();
19446    }
19447
19448    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19449        self.show_gutter = show_gutter;
19450        cx.notify();
19451    }
19452
19453    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19454        self.show_scrollbars = ScrollbarAxes {
19455            horizontal: show,
19456            vertical: show,
19457        };
19458        cx.notify();
19459    }
19460
19461    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19462        self.show_scrollbars.vertical = show;
19463        cx.notify();
19464    }
19465
19466    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19467        self.show_scrollbars.horizontal = show;
19468        cx.notify();
19469    }
19470
19471    pub fn set_minimap_visibility(
19472        &mut self,
19473        minimap_visibility: MinimapVisibility,
19474        window: &mut Window,
19475        cx: &mut Context<Self>,
19476    ) {
19477        if self.minimap_visibility != minimap_visibility {
19478            if minimap_visibility.visible() && self.minimap.is_none() {
19479                let minimap_settings = EditorSettings::get_global(cx).minimap;
19480                self.minimap =
19481                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19482            }
19483            self.minimap_visibility = minimap_visibility;
19484            cx.notify();
19485        }
19486    }
19487
19488    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19489        self.set_show_scrollbars(false, cx);
19490        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19491    }
19492
19493    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19494        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19495    }
19496
19497    /// Normally the text in full mode and auto height editors is padded on the
19498    /// left side by roughly half a character width for improved hit testing.
19499    ///
19500    /// Use this method to disable this for cases where this is not wanted (e.g.
19501    /// if you want to align the editor text with some other text above or below)
19502    /// or if you want to add this padding to single-line editors.
19503    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19504        self.offset_content = offset_content;
19505        cx.notify();
19506    }
19507
19508    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19509        self.show_line_numbers = Some(show_line_numbers);
19510        cx.notify();
19511    }
19512
19513    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19514        self.disable_expand_excerpt_buttons = true;
19515        cx.notify();
19516    }
19517
19518    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19519        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19520        cx.notify();
19521    }
19522
19523    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19524        self.show_code_actions = Some(show_code_actions);
19525        cx.notify();
19526    }
19527
19528    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19529        self.show_runnables = Some(show_runnables);
19530        cx.notify();
19531    }
19532
19533    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19534        self.show_breakpoints = Some(show_breakpoints);
19535        cx.notify();
19536    }
19537
19538    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19539        if self.display_map.read(cx).masked != masked {
19540            self.display_map.update(cx, |map, _| map.masked = masked);
19541        }
19542        cx.notify()
19543    }
19544
19545    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19546        self.show_wrap_guides = Some(show_wrap_guides);
19547        cx.notify();
19548    }
19549
19550    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19551        self.show_indent_guides = Some(show_indent_guides);
19552        cx.notify();
19553    }
19554
19555    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19556        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19557            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19558                && let Some(dir) = file.abs_path(cx).parent()
19559            {
19560                return Some(dir.to_owned());
19561            }
19562        }
19563
19564        None
19565    }
19566
19567    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19568        self.active_excerpt(cx)?
19569            .1
19570            .read(cx)
19571            .file()
19572            .and_then(|f| f.as_local())
19573    }
19574
19575    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19576        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19577            let buffer = buffer.read(cx);
19578            if let Some(project_path) = buffer.project_path(cx) {
19579                let project = self.project()?.read(cx);
19580                project.absolute_path(&project_path, cx)
19581            } else {
19582                buffer
19583                    .file()
19584                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19585            }
19586        })
19587    }
19588
19589    pub fn reveal_in_finder(
19590        &mut self,
19591        _: &RevealInFileManager,
19592        _window: &mut Window,
19593        cx: &mut Context<Self>,
19594    ) {
19595        if let Some(target) = self.target_file(cx) {
19596            cx.reveal_path(&target.abs_path(cx));
19597        }
19598    }
19599
19600    pub fn copy_path(
19601        &mut self,
19602        _: &zed_actions::workspace::CopyPath,
19603        _window: &mut Window,
19604        cx: &mut Context<Self>,
19605    ) {
19606        if let Some(path) = self.target_file_abs_path(cx)
19607            && let Some(path) = path.to_str()
19608        {
19609            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19610        } else {
19611            cx.propagate();
19612        }
19613    }
19614
19615    pub fn copy_relative_path(
19616        &mut self,
19617        _: &zed_actions::workspace::CopyRelativePath,
19618        _window: &mut Window,
19619        cx: &mut Context<Self>,
19620    ) {
19621        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19622            let project = self.project()?.read(cx);
19623            let path = buffer.read(cx).file()?.path();
19624            let path = path.display(project.path_style(cx));
19625            Some(path)
19626        }) {
19627            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19628        } else {
19629            cx.propagate();
19630        }
19631    }
19632
19633    /// Returns the project path for the editor's buffer, if any buffer is
19634    /// opened in the editor.
19635    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19636        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19637            buffer.read(cx).project_path(cx)
19638        } else {
19639            None
19640        }
19641    }
19642
19643    // Returns true if the editor handled a go-to-line request
19644    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19645        maybe!({
19646            let breakpoint_store = self.breakpoint_store.as_ref()?;
19647
19648            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19649            else {
19650                self.clear_row_highlights::<ActiveDebugLine>();
19651                return None;
19652            };
19653
19654            let position = active_stack_frame.position;
19655            let buffer_id = position.buffer_id?;
19656            let snapshot = self
19657                .project
19658                .as_ref()?
19659                .read(cx)
19660                .buffer_for_id(buffer_id, cx)?
19661                .read(cx)
19662                .snapshot();
19663
19664            let mut handled = false;
19665            for (id, ExcerptRange { context, .. }) in
19666                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19667            {
19668                if context.start.cmp(&position, &snapshot).is_ge()
19669                    || context.end.cmp(&position, &snapshot).is_lt()
19670                {
19671                    continue;
19672                }
19673                let snapshot = self.buffer.read(cx).snapshot(cx);
19674                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19675
19676                handled = true;
19677                self.clear_row_highlights::<ActiveDebugLine>();
19678
19679                self.go_to_line::<ActiveDebugLine>(
19680                    multibuffer_anchor,
19681                    Some(cx.theme().colors().editor_debugger_active_line_background),
19682                    window,
19683                    cx,
19684                );
19685
19686                cx.notify();
19687            }
19688
19689            handled.then_some(())
19690        })
19691        .is_some()
19692    }
19693
19694    pub fn copy_file_name_without_extension(
19695        &mut self,
19696        _: &CopyFileNameWithoutExtension,
19697        _: &mut Window,
19698        cx: &mut Context<Self>,
19699    ) {
19700        if let Some(file) = self.target_file(cx)
19701            && let Some(file_stem) = file.path().file_stem()
19702        {
19703            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19704        }
19705    }
19706
19707    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19708        if let Some(file) = self.target_file(cx)
19709            && let Some(name) = file.path().file_name()
19710        {
19711            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19712        }
19713    }
19714
19715    pub fn toggle_git_blame(
19716        &mut self,
19717        _: &::git::Blame,
19718        window: &mut Window,
19719        cx: &mut Context<Self>,
19720    ) {
19721        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19722
19723        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19724            self.start_git_blame(true, window, cx);
19725        }
19726
19727        cx.notify();
19728    }
19729
19730    pub fn toggle_git_blame_inline(
19731        &mut self,
19732        _: &ToggleGitBlameInline,
19733        window: &mut Window,
19734        cx: &mut Context<Self>,
19735    ) {
19736        self.toggle_git_blame_inline_internal(true, window, cx);
19737        cx.notify();
19738    }
19739
19740    pub fn open_git_blame_commit(
19741        &mut self,
19742        _: &OpenGitBlameCommit,
19743        window: &mut Window,
19744        cx: &mut Context<Self>,
19745    ) {
19746        self.open_git_blame_commit_internal(window, cx);
19747    }
19748
19749    fn open_git_blame_commit_internal(
19750        &mut self,
19751        window: &mut Window,
19752        cx: &mut Context<Self>,
19753    ) -> Option<()> {
19754        let blame = self.blame.as_ref()?;
19755        let snapshot = self.snapshot(window, cx);
19756        let cursor = self.selections.newest::<Point>(cx).head();
19757        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19758        let (_, blame_entry) = blame
19759            .update(cx, |blame, cx| {
19760                blame
19761                    .blame_for_rows(
19762                        &[RowInfo {
19763                            buffer_id: Some(buffer.remote_id()),
19764                            buffer_row: Some(point.row),
19765                            ..Default::default()
19766                        }],
19767                        cx,
19768                    )
19769                    .next()
19770            })
19771            .flatten()?;
19772        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19773        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19774        let workspace = self.workspace()?.downgrade();
19775        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19776        None
19777    }
19778
19779    pub fn git_blame_inline_enabled(&self) -> bool {
19780        self.git_blame_inline_enabled
19781    }
19782
19783    pub fn toggle_selection_menu(
19784        &mut self,
19785        _: &ToggleSelectionMenu,
19786        _: &mut Window,
19787        cx: &mut Context<Self>,
19788    ) {
19789        self.show_selection_menu = self
19790            .show_selection_menu
19791            .map(|show_selections_menu| !show_selections_menu)
19792            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19793
19794        cx.notify();
19795    }
19796
19797    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19798        self.show_selection_menu
19799            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19800    }
19801
19802    fn start_git_blame(
19803        &mut self,
19804        user_triggered: bool,
19805        window: &mut Window,
19806        cx: &mut Context<Self>,
19807    ) {
19808        if let Some(project) = self.project() {
19809            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19810                && buffer.read(cx).file().is_none()
19811            {
19812                return;
19813            }
19814
19815            let focused = self.focus_handle(cx).contains_focused(window, cx);
19816
19817            let project = project.clone();
19818            let blame = cx
19819                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19820            self.blame_subscription =
19821                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19822            self.blame = Some(blame);
19823        }
19824    }
19825
19826    fn toggle_git_blame_inline_internal(
19827        &mut self,
19828        user_triggered: bool,
19829        window: &mut Window,
19830        cx: &mut Context<Self>,
19831    ) {
19832        if self.git_blame_inline_enabled {
19833            self.git_blame_inline_enabled = false;
19834            self.show_git_blame_inline = false;
19835            self.show_git_blame_inline_delay_task.take();
19836        } else {
19837            self.git_blame_inline_enabled = true;
19838            self.start_git_blame_inline(user_triggered, window, cx);
19839        }
19840
19841        cx.notify();
19842    }
19843
19844    fn start_git_blame_inline(
19845        &mut self,
19846        user_triggered: bool,
19847        window: &mut Window,
19848        cx: &mut Context<Self>,
19849    ) {
19850        self.start_git_blame(user_triggered, window, cx);
19851
19852        if ProjectSettings::get_global(cx)
19853            .git
19854            .inline_blame_delay()
19855            .is_some()
19856        {
19857            self.start_inline_blame_timer(window, cx);
19858        } else {
19859            self.show_git_blame_inline = true
19860        }
19861    }
19862
19863    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19864        self.blame.as_ref()
19865    }
19866
19867    pub fn show_git_blame_gutter(&self) -> bool {
19868        self.show_git_blame_gutter
19869    }
19870
19871    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19872        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19873    }
19874
19875    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19876        self.show_git_blame_inline
19877            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19878            && !self.newest_selection_head_on_empty_line(cx)
19879            && self.has_blame_entries(cx)
19880    }
19881
19882    fn has_blame_entries(&self, cx: &App) -> bool {
19883        self.blame()
19884            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19885    }
19886
19887    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19888        let cursor_anchor = self.selections.newest_anchor().head();
19889
19890        let snapshot = self.buffer.read(cx).snapshot(cx);
19891        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19892
19893        snapshot.line_len(buffer_row) == 0
19894    }
19895
19896    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19897        let buffer_and_selection = maybe!({
19898            let selection = self.selections.newest::<Point>(cx);
19899            let selection_range = selection.range();
19900
19901            let multi_buffer = self.buffer().read(cx);
19902            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19903            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19904
19905            let (buffer, range, _) = if selection.reversed {
19906                buffer_ranges.first()
19907            } else {
19908                buffer_ranges.last()
19909            }?;
19910
19911            let selection = text::ToPoint::to_point(&range.start, buffer).row
19912                ..text::ToPoint::to_point(&range.end, buffer).row;
19913            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19914        });
19915
19916        let Some((buffer, selection)) = buffer_and_selection else {
19917            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19918        };
19919
19920        let Some(project) = self.project() else {
19921            return Task::ready(Err(anyhow!("editor does not have project")));
19922        };
19923
19924        project.update(cx, |project, cx| {
19925            project.get_permalink_to_line(&buffer, selection, cx)
19926        })
19927    }
19928
19929    pub fn copy_permalink_to_line(
19930        &mut self,
19931        _: &CopyPermalinkToLine,
19932        window: &mut Window,
19933        cx: &mut Context<Self>,
19934    ) {
19935        let permalink_task = self.get_permalink_to_line(cx);
19936        let workspace = self.workspace();
19937
19938        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19939            Ok(permalink) => {
19940                cx.update(|_, cx| {
19941                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19942                })
19943                .ok();
19944            }
19945            Err(err) => {
19946                let message = format!("Failed to copy permalink: {err}");
19947
19948                anyhow::Result::<()>::Err(err).log_err();
19949
19950                if let Some(workspace) = workspace {
19951                    workspace
19952                        .update_in(cx, |workspace, _, cx| {
19953                            struct CopyPermalinkToLine;
19954
19955                            workspace.show_toast(
19956                                Toast::new(
19957                                    NotificationId::unique::<CopyPermalinkToLine>(),
19958                                    message,
19959                                ),
19960                                cx,
19961                            )
19962                        })
19963                        .ok();
19964                }
19965            }
19966        })
19967        .detach();
19968    }
19969
19970    pub fn copy_file_location(
19971        &mut self,
19972        _: &CopyFileLocation,
19973        _: &mut Window,
19974        cx: &mut Context<Self>,
19975    ) {
19976        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19977        if let Some(file) = self.target_file(cx) {
19978            let path = file.path().display(file.path_style(cx));
19979            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19980        }
19981    }
19982
19983    pub fn open_permalink_to_line(
19984        &mut self,
19985        _: &OpenPermalinkToLine,
19986        window: &mut Window,
19987        cx: &mut Context<Self>,
19988    ) {
19989        let permalink_task = self.get_permalink_to_line(cx);
19990        let workspace = self.workspace();
19991
19992        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19993            Ok(permalink) => {
19994                cx.update(|_, cx| {
19995                    cx.open_url(permalink.as_ref());
19996                })
19997                .ok();
19998            }
19999            Err(err) => {
20000                let message = format!("Failed to open permalink: {err}");
20001
20002                anyhow::Result::<()>::Err(err).log_err();
20003
20004                if let Some(workspace) = workspace {
20005                    workspace
20006                        .update(cx, |workspace, cx| {
20007                            struct OpenPermalinkToLine;
20008
20009                            workspace.show_toast(
20010                                Toast::new(
20011                                    NotificationId::unique::<OpenPermalinkToLine>(),
20012                                    message,
20013                                ),
20014                                cx,
20015                            )
20016                        })
20017                        .ok();
20018                }
20019            }
20020        })
20021        .detach();
20022    }
20023
20024    pub fn insert_uuid_v4(
20025        &mut self,
20026        _: &InsertUuidV4,
20027        window: &mut Window,
20028        cx: &mut Context<Self>,
20029    ) {
20030        self.insert_uuid(UuidVersion::V4, window, cx);
20031    }
20032
20033    pub fn insert_uuid_v7(
20034        &mut self,
20035        _: &InsertUuidV7,
20036        window: &mut Window,
20037        cx: &mut Context<Self>,
20038    ) {
20039        self.insert_uuid(UuidVersion::V7, window, cx);
20040    }
20041
20042    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20043        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20044        self.transact(window, cx, |this, window, cx| {
20045            let edits = this
20046                .selections
20047                .all::<Point>(cx)
20048                .into_iter()
20049                .map(|selection| {
20050                    let uuid = match version {
20051                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20052                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20053                    };
20054
20055                    (selection.range(), uuid.to_string())
20056                });
20057            this.edit(edits, cx);
20058            this.refresh_edit_prediction(true, false, window, cx);
20059        });
20060    }
20061
20062    pub fn open_selections_in_multibuffer(
20063        &mut self,
20064        _: &OpenSelectionsInMultibuffer,
20065        window: &mut Window,
20066        cx: &mut Context<Self>,
20067    ) {
20068        let multibuffer = self.buffer.read(cx);
20069
20070        let Some(buffer) = multibuffer.as_singleton() else {
20071            return;
20072        };
20073
20074        let Some(workspace) = self.workspace() else {
20075            return;
20076        };
20077
20078        let title = multibuffer.title(cx).to_string();
20079
20080        let locations = self
20081            .selections
20082            .all_anchors(cx)
20083            .iter()
20084            .map(|selection| {
20085                (
20086                    buffer.clone(),
20087                    (selection.start.text_anchor..selection.end.text_anchor)
20088                        .to_point(buffer.read(cx)),
20089                )
20090            })
20091            .into_group_map();
20092
20093        cx.spawn_in(window, async move |_, cx| {
20094            workspace.update_in(cx, |workspace, window, cx| {
20095                Self::open_locations_in_multibuffer(
20096                    workspace,
20097                    locations,
20098                    format!("Selections for '{title}'"),
20099                    false,
20100                    MultibufferSelectionMode::All,
20101                    window,
20102                    cx,
20103                );
20104            })
20105        })
20106        .detach();
20107    }
20108
20109    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20110    /// last highlight added will be used.
20111    ///
20112    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20113    pub fn highlight_rows<T: 'static>(
20114        &mut self,
20115        range: Range<Anchor>,
20116        color: Hsla,
20117        options: RowHighlightOptions,
20118        cx: &mut Context<Self>,
20119    ) {
20120        let snapshot = self.buffer().read(cx).snapshot(cx);
20121        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20122        let ix = row_highlights.binary_search_by(|highlight| {
20123            Ordering::Equal
20124                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20125                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20126        });
20127
20128        if let Err(mut ix) = ix {
20129            let index = post_inc(&mut self.highlight_order);
20130
20131            // If this range intersects with the preceding highlight, then merge it with
20132            // the preceding highlight. Otherwise insert a new highlight.
20133            let mut merged = false;
20134            if ix > 0 {
20135                let prev_highlight = &mut row_highlights[ix - 1];
20136                if prev_highlight
20137                    .range
20138                    .end
20139                    .cmp(&range.start, &snapshot)
20140                    .is_ge()
20141                {
20142                    ix -= 1;
20143                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20144                        prev_highlight.range.end = range.end;
20145                    }
20146                    merged = true;
20147                    prev_highlight.index = index;
20148                    prev_highlight.color = color;
20149                    prev_highlight.options = options;
20150                }
20151            }
20152
20153            if !merged {
20154                row_highlights.insert(
20155                    ix,
20156                    RowHighlight {
20157                        range,
20158                        index,
20159                        color,
20160                        options,
20161                        type_id: TypeId::of::<T>(),
20162                    },
20163                );
20164            }
20165
20166            // If any of the following highlights intersect with this one, merge them.
20167            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20168                let highlight = &row_highlights[ix];
20169                if next_highlight
20170                    .range
20171                    .start
20172                    .cmp(&highlight.range.end, &snapshot)
20173                    .is_le()
20174                {
20175                    if next_highlight
20176                        .range
20177                        .end
20178                        .cmp(&highlight.range.end, &snapshot)
20179                        .is_gt()
20180                    {
20181                        row_highlights[ix].range.end = next_highlight.range.end;
20182                    }
20183                    row_highlights.remove(ix + 1);
20184                } else {
20185                    break;
20186                }
20187            }
20188        }
20189    }
20190
20191    /// Remove any highlighted row ranges of the given type that intersect the
20192    /// given ranges.
20193    pub fn remove_highlighted_rows<T: 'static>(
20194        &mut self,
20195        ranges_to_remove: Vec<Range<Anchor>>,
20196        cx: &mut Context<Self>,
20197    ) {
20198        let snapshot = self.buffer().read(cx).snapshot(cx);
20199        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20200        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20201        row_highlights.retain(|highlight| {
20202            while let Some(range_to_remove) = ranges_to_remove.peek() {
20203                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20204                    Ordering::Less | Ordering::Equal => {
20205                        ranges_to_remove.next();
20206                    }
20207                    Ordering::Greater => {
20208                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20209                            Ordering::Less | Ordering::Equal => {
20210                                return false;
20211                            }
20212                            Ordering::Greater => break,
20213                        }
20214                    }
20215                }
20216            }
20217
20218            true
20219        })
20220    }
20221
20222    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20223    pub fn clear_row_highlights<T: 'static>(&mut self) {
20224        self.highlighted_rows.remove(&TypeId::of::<T>());
20225    }
20226
20227    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20228    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20229        self.highlighted_rows
20230            .get(&TypeId::of::<T>())
20231            .map_or(&[] as &[_], |vec| vec.as_slice())
20232            .iter()
20233            .map(|highlight| (highlight.range.clone(), highlight.color))
20234    }
20235
20236    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20237    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20238    /// Allows to ignore certain kinds of highlights.
20239    pub fn highlighted_display_rows(
20240        &self,
20241        window: &mut Window,
20242        cx: &mut App,
20243    ) -> BTreeMap<DisplayRow, LineHighlight> {
20244        let snapshot = self.snapshot(window, cx);
20245        let mut used_highlight_orders = HashMap::default();
20246        self.highlighted_rows
20247            .iter()
20248            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20249            .fold(
20250                BTreeMap::<DisplayRow, LineHighlight>::new(),
20251                |mut unique_rows, highlight| {
20252                    let start = highlight.range.start.to_display_point(&snapshot);
20253                    let end = highlight.range.end.to_display_point(&snapshot);
20254                    let start_row = start.row().0;
20255                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20256                        && end.column() == 0
20257                    {
20258                        end.row().0.saturating_sub(1)
20259                    } else {
20260                        end.row().0
20261                    };
20262                    for row in start_row..=end_row {
20263                        let used_index =
20264                            used_highlight_orders.entry(row).or_insert(highlight.index);
20265                        if highlight.index >= *used_index {
20266                            *used_index = highlight.index;
20267                            unique_rows.insert(
20268                                DisplayRow(row),
20269                                LineHighlight {
20270                                    include_gutter: highlight.options.include_gutter,
20271                                    border: None,
20272                                    background: highlight.color.into(),
20273                                    type_id: Some(highlight.type_id),
20274                                },
20275                            );
20276                        }
20277                    }
20278                    unique_rows
20279                },
20280            )
20281    }
20282
20283    pub fn highlighted_display_row_for_autoscroll(
20284        &self,
20285        snapshot: &DisplaySnapshot,
20286    ) -> Option<DisplayRow> {
20287        self.highlighted_rows
20288            .values()
20289            .flat_map(|highlighted_rows| highlighted_rows.iter())
20290            .filter_map(|highlight| {
20291                if highlight.options.autoscroll {
20292                    Some(highlight.range.start.to_display_point(snapshot).row())
20293                } else {
20294                    None
20295                }
20296            })
20297            .min()
20298    }
20299
20300    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20301        self.highlight_background::<SearchWithinRange>(
20302            ranges,
20303            |colors| colors.colors().editor_document_highlight_read_background,
20304            cx,
20305        )
20306    }
20307
20308    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20309        self.breadcrumb_header = Some(new_header);
20310    }
20311
20312    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20313        self.clear_background_highlights::<SearchWithinRange>(cx);
20314    }
20315
20316    pub fn highlight_background<T: 'static>(
20317        &mut self,
20318        ranges: &[Range<Anchor>],
20319        color_fetcher: fn(&Theme) -> Hsla,
20320        cx: &mut Context<Self>,
20321    ) {
20322        self.background_highlights.insert(
20323            HighlightKey::Type(TypeId::of::<T>()),
20324            (color_fetcher, Arc::from(ranges)),
20325        );
20326        self.scrollbar_marker_state.dirty = true;
20327        cx.notify();
20328    }
20329
20330    pub fn highlight_background_key<T: 'static>(
20331        &mut self,
20332        key: usize,
20333        ranges: &[Range<Anchor>],
20334        color_fetcher: fn(&Theme) -> Hsla,
20335        cx: &mut Context<Self>,
20336    ) {
20337        self.background_highlights.insert(
20338            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20339            (color_fetcher, Arc::from(ranges)),
20340        );
20341        self.scrollbar_marker_state.dirty = true;
20342        cx.notify();
20343    }
20344
20345    pub fn clear_background_highlights<T: 'static>(
20346        &mut self,
20347        cx: &mut Context<Self>,
20348    ) -> Option<BackgroundHighlight> {
20349        let text_highlights = self
20350            .background_highlights
20351            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20352        if !text_highlights.1.is_empty() {
20353            self.scrollbar_marker_state.dirty = true;
20354            cx.notify();
20355        }
20356        Some(text_highlights)
20357    }
20358
20359    pub fn highlight_gutter<T: 'static>(
20360        &mut self,
20361        ranges: impl Into<Vec<Range<Anchor>>>,
20362        color_fetcher: fn(&App) -> Hsla,
20363        cx: &mut Context<Self>,
20364    ) {
20365        self.gutter_highlights
20366            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20367        cx.notify();
20368    }
20369
20370    pub fn clear_gutter_highlights<T: 'static>(
20371        &mut self,
20372        cx: &mut Context<Self>,
20373    ) -> Option<GutterHighlight> {
20374        cx.notify();
20375        self.gutter_highlights.remove(&TypeId::of::<T>())
20376    }
20377
20378    pub fn insert_gutter_highlight<T: 'static>(
20379        &mut self,
20380        range: Range<Anchor>,
20381        color_fetcher: fn(&App) -> Hsla,
20382        cx: &mut Context<Self>,
20383    ) {
20384        let snapshot = self.buffer().read(cx).snapshot(cx);
20385        let mut highlights = self
20386            .gutter_highlights
20387            .remove(&TypeId::of::<T>())
20388            .map(|(_, highlights)| highlights)
20389            .unwrap_or_default();
20390        let ix = highlights.binary_search_by(|highlight| {
20391            Ordering::Equal
20392                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20393                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20394        });
20395        if let Err(ix) = ix {
20396            highlights.insert(ix, range);
20397        }
20398        self.gutter_highlights
20399            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20400    }
20401
20402    pub fn remove_gutter_highlights<T: 'static>(
20403        &mut self,
20404        ranges_to_remove: Vec<Range<Anchor>>,
20405        cx: &mut Context<Self>,
20406    ) {
20407        let snapshot = self.buffer().read(cx).snapshot(cx);
20408        let Some((color_fetcher, mut gutter_highlights)) =
20409            self.gutter_highlights.remove(&TypeId::of::<T>())
20410        else {
20411            return;
20412        };
20413        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20414        gutter_highlights.retain(|highlight| {
20415            while let Some(range_to_remove) = ranges_to_remove.peek() {
20416                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20417                    Ordering::Less | Ordering::Equal => {
20418                        ranges_to_remove.next();
20419                    }
20420                    Ordering::Greater => {
20421                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20422                            Ordering::Less | Ordering::Equal => {
20423                                return false;
20424                            }
20425                            Ordering::Greater => break,
20426                        }
20427                    }
20428                }
20429            }
20430
20431            true
20432        });
20433        self.gutter_highlights
20434            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20435    }
20436
20437    #[cfg(feature = "test-support")]
20438    pub fn all_text_highlights(
20439        &self,
20440        window: &mut Window,
20441        cx: &mut Context<Self>,
20442    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20443        let snapshot = self.snapshot(window, cx);
20444        self.display_map.update(cx, |display_map, _| {
20445            display_map
20446                .all_text_highlights()
20447                .map(|highlight| {
20448                    let (style, ranges) = highlight.as_ref();
20449                    (
20450                        *style,
20451                        ranges
20452                            .iter()
20453                            .map(|range| range.clone().to_display_points(&snapshot))
20454                            .collect(),
20455                    )
20456                })
20457                .collect()
20458        })
20459    }
20460
20461    #[cfg(feature = "test-support")]
20462    pub fn all_text_background_highlights(
20463        &self,
20464        window: &mut Window,
20465        cx: &mut Context<Self>,
20466    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20467        let snapshot = self.snapshot(window, cx);
20468        let buffer = &snapshot.buffer_snapshot();
20469        let start = buffer.anchor_before(0);
20470        let end = buffer.anchor_after(buffer.len());
20471        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20472    }
20473
20474    #[cfg(any(test, feature = "test-support"))]
20475    pub fn sorted_background_highlights_in_range(
20476        &self,
20477        search_range: Range<Anchor>,
20478        display_snapshot: &DisplaySnapshot,
20479        theme: &Theme,
20480    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20481        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20482        res.sort_by(|a, b| {
20483            a.0.start
20484                .cmp(&b.0.start)
20485                .then_with(|| a.0.end.cmp(&b.0.end))
20486                .then_with(|| a.1.cmp(&b.1))
20487        });
20488        res
20489    }
20490
20491    #[cfg(feature = "test-support")]
20492    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20493        let snapshot = self.buffer().read(cx).snapshot(cx);
20494
20495        let highlights = self
20496            .background_highlights
20497            .get(&HighlightKey::Type(TypeId::of::<
20498                items::BufferSearchHighlights,
20499            >()));
20500
20501        if let Some((_color, ranges)) = highlights {
20502            ranges
20503                .iter()
20504                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20505                .collect_vec()
20506        } else {
20507            vec![]
20508        }
20509    }
20510
20511    fn document_highlights_for_position<'a>(
20512        &'a self,
20513        position: Anchor,
20514        buffer: &'a MultiBufferSnapshot,
20515    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20516        let read_highlights = self
20517            .background_highlights
20518            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20519            .map(|h| &h.1);
20520        let write_highlights = self
20521            .background_highlights
20522            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20523            .map(|h| &h.1);
20524        let left_position = position.bias_left(buffer);
20525        let right_position = position.bias_right(buffer);
20526        read_highlights
20527            .into_iter()
20528            .chain(write_highlights)
20529            .flat_map(move |ranges| {
20530                let start_ix = match ranges.binary_search_by(|probe| {
20531                    let cmp = probe.end.cmp(&left_position, buffer);
20532                    if cmp.is_ge() {
20533                        Ordering::Greater
20534                    } else {
20535                        Ordering::Less
20536                    }
20537                }) {
20538                    Ok(i) | Err(i) => i,
20539                };
20540
20541                ranges[start_ix..]
20542                    .iter()
20543                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20544            })
20545    }
20546
20547    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20548        self.background_highlights
20549            .get(&HighlightKey::Type(TypeId::of::<T>()))
20550            .is_some_and(|(_, highlights)| !highlights.is_empty())
20551    }
20552
20553    /// Returns all background highlights for a given range.
20554    ///
20555    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20556    pub fn background_highlights_in_range(
20557        &self,
20558        search_range: Range<Anchor>,
20559        display_snapshot: &DisplaySnapshot,
20560        theme: &Theme,
20561    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20562        let mut results = Vec::new();
20563        for (color_fetcher, ranges) in self.background_highlights.values() {
20564            let color = color_fetcher(theme);
20565            let start_ix = match ranges.binary_search_by(|probe| {
20566                let cmp = probe
20567                    .end
20568                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20569                if cmp.is_gt() {
20570                    Ordering::Greater
20571                } else {
20572                    Ordering::Less
20573                }
20574            }) {
20575                Ok(i) | Err(i) => i,
20576            };
20577            for range in &ranges[start_ix..] {
20578                if range
20579                    .start
20580                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20581                    .is_ge()
20582                {
20583                    break;
20584                }
20585
20586                let start = range.start.to_display_point(display_snapshot);
20587                let end = range.end.to_display_point(display_snapshot);
20588                results.push((start..end, color))
20589            }
20590        }
20591        results
20592    }
20593
20594    pub fn gutter_highlights_in_range(
20595        &self,
20596        search_range: Range<Anchor>,
20597        display_snapshot: &DisplaySnapshot,
20598        cx: &App,
20599    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20600        let mut results = Vec::new();
20601        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20602            let color = color_fetcher(cx);
20603            let start_ix = match ranges.binary_search_by(|probe| {
20604                let cmp = probe
20605                    .end
20606                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20607                if cmp.is_gt() {
20608                    Ordering::Greater
20609                } else {
20610                    Ordering::Less
20611                }
20612            }) {
20613                Ok(i) | Err(i) => i,
20614            };
20615            for range in &ranges[start_ix..] {
20616                if range
20617                    .start
20618                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20619                    .is_ge()
20620                {
20621                    break;
20622                }
20623
20624                let start = range.start.to_display_point(display_snapshot);
20625                let end = range.end.to_display_point(display_snapshot);
20626                results.push((start..end, color))
20627            }
20628        }
20629        results
20630    }
20631
20632    /// Get the text ranges corresponding to the redaction query
20633    pub fn redacted_ranges(
20634        &self,
20635        search_range: Range<Anchor>,
20636        display_snapshot: &DisplaySnapshot,
20637        cx: &App,
20638    ) -> Vec<Range<DisplayPoint>> {
20639        display_snapshot
20640            .buffer_snapshot()
20641            .redacted_ranges(search_range, |file| {
20642                if let Some(file) = file {
20643                    file.is_private()
20644                        && EditorSettings::get(
20645                            Some(SettingsLocation {
20646                                worktree_id: file.worktree_id(cx),
20647                                path: file.path().as_ref(),
20648                            }),
20649                            cx,
20650                        )
20651                        .redact_private_values
20652                } else {
20653                    false
20654                }
20655            })
20656            .map(|range| {
20657                range.start.to_display_point(display_snapshot)
20658                    ..range.end.to_display_point(display_snapshot)
20659            })
20660            .collect()
20661    }
20662
20663    pub fn highlight_text_key<T: 'static>(
20664        &mut self,
20665        key: usize,
20666        ranges: Vec<Range<Anchor>>,
20667        style: HighlightStyle,
20668        cx: &mut Context<Self>,
20669    ) {
20670        self.display_map.update(cx, |map, _| {
20671            map.highlight_text(
20672                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20673                ranges,
20674                style,
20675            );
20676        });
20677        cx.notify();
20678    }
20679
20680    pub fn highlight_text<T: 'static>(
20681        &mut self,
20682        ranges: Vec<Range<Anchor>>,
20683        style: HighlightStyle,
20684        cx: &mut Context<Self>,
20685    ) {
20686        self.display_map.update(cx, |map, _| {
20687            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20688        });
20689        cx.notify();
20690    }
20691
20692    pub(crate) fn highlight_inlays<T: 'static>(
20693        &mut self,
20694        highlights: Vec<InlayHighlight>,
20695        style: HighlightStyle,
20696        cx: &mut Context<Self>,
20697    ) {
20698        self.display_map.update(cx, |map, _| {
20699            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20700        });
20701        cx.notify();
20702    }
20703
20704    pub fn text_highlights<'a, T: 'static>(
20705        &'a self,
20706        cx: &'a App,
20707    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20708        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20709    }
20710
20711    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20712        let cleared = self
20713            .display_map
20714            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20715        if cleared {
20716            cx.notify();
20717        }
20718    }
20719
20720    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20721        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20722            && self.focus_handle.is_focused(window)
20723    }
20724
20725    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20726        self.show_cursor_when_unfocused = is_enabled;
20727        cx.notify();
20728    }
20729
20730    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20731        cx.notify();
20732    }
20733
20734    fn on_debug_session_event(
20735        &mut self,
20736        _session: Entity<Session>,
20737        event: &SessionEvent,
20738        cx: &mut Context<Self>,
20739    ) {
20740        if let SessionEvent::InvalidateInlineValue = event {
20741            self.refresh_inline_values(cx);
20742        }
20743    }
20744
20745    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20746        let Some(project) = self.project.clone() else {
20747            return;
20748        };
20749
20750        if !self.inline_value_cache.enabled {
20751            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20752            self.splice_inlays(&inlays, Vec::new(), cx);
20753            return;
20754        }
20755
20756        let current_execution_position = self
20757            .highlighted_rows
20758            .get(&TypeId::of::<ActiveDebugLine>())
20759            .and_then(|lines| lines.last().map(|line| line.range.end));
20760
20761        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20762            let inline_values = editor
20763                .update(cx, |editor, cx| {
20764                    let Some(current_execution_position) = current_execution_position else {
20765                        return Some(Task::ready(Ok(Vec::new())));
20766                    };
20767
20768                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20769                        let snapshot = buffer.snapshot(cx);
20770
20771                        let excerpt = snapshot.excerpt_containing(
20772                            current_execution_position..current_execution_position,
20773                        )?;
20774
20775                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20776                    })?;
20777
20778                    let range =
20779                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20780
20781                    project.inline_values(buffer, range, cx)
20782                })
20783                .ok()
20784                .flatten()?
20785                .await
20786                .context("refreshing debugger inlays")
20787                .log_err()?;
20788
20789            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20790
20791            for (buffer_id, inline_value) in inline_values
20792                .into_iter()
20793                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20794            {
20795                buffer_inline_values
20796                    .entry(buffer_id)
20797                    .or_default()
20798                    .push(inline_value);
20799            }
20800
20801            editor
20802                .update(cx, |editor, cx| {
20803                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20804                    let mut new_inlays = Vec::default();
20805
20806                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20807                        let buffer_id = buffer_snapshot.remote_id();
20808                        buffer_inline_values
20809                            .get(&buffer_id)
20810                            .into_iter()
20811                            .flatten()
20812                            .for_each(|hint| {
20813                                let inlay = Inlay::debugger(
20814                                    post_inc(&mut editor.next_inlay_id),
20815                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20816                                    hint.text(),
20817                                );
20818                                if !inlay.text().chars().contains(&'\n') {
20819                                    new_inlays.push(inlay);
20820                                }
20821                            });
20822                    }
20823
20824                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20825                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20826
20827                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20828                })
20829                .ok()?;
20830            Some(())
20831        });
20832    }
20833
20834    fn on_buffer_event(
20835        &mut self,
20836        multibuffer: &Entity<MultiBuffer>,
20837        event: &multi_buffer::Event,
20838        window: &mut Window,
20839        cx: &mut Context<Self>,
20840    ) {
20841        match event {
20842            multi_buffer::Event::Edited { edited_buffer } => {
20843                self.scrollbar_marker_state.dirty = true;
20844                self.active_indent_guides_state.dirty = true;
20845                self.refresh_active_diagnostics(cx);
20846                self.refresh_code_actions(window, cx);
20847                self.refresh_selected_text_highlights(true, window, cx);
20848                self.refresh_single_line_folds(window, cx);
20849                refresh_matching_bracket_highlights(self, cx);
20850                if self.has_active_edit_prediction() {
20851                    self.update_visible_edit_prediction(window, cx);
20852                }
20853
20854                if let Some(edited_buffer) = edited_buffer {
20855                    if edited_buffer.read(cx).file().is_none() {
20856                        cx.emit(EditorEvent::TitleChanged);
20857                    }
20858
20859                    let buffer_id = edited_buffer.read(cx).remote_id();
20860                    if let Some(project) = self.project.clone() {
20861                        self.register_buffer(buffer_id, cx);
20862                        self.update_lsp_data(Some(buffer_id), window, cx);
20863                        #[allow(clippy::mutable_key_type)]
20864                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20865                            multibuffer
20866                                .all_buffers()
20867                                .into_iter()
20868                                .filter_map(|buffer| {
20869                                    buffer.update(cx, |buffer, cx| {
20870                                        let language = buffer.language()?;
20871                                        let should_discard = project.update(cx, |project, cx| {
20872                                            project.is_local()
20873                                                && !project.has_language_servers_for(buffer, cx)
20874                                        });
20875                                        should_discard.not().then_some(language.clone())
20876                                    })
20877                                })
20878                                .collect::<HashSet<_>>()
20879                        });
20880                        if !languages_affected.is_empty() {
20881                            self.refresh_inlay_hints(
20882                                InlayHintRefreshReason::BufferEdited(languages_affected),
20883                                cx,
20884                            );
20885                        }
20886                    }
20887                }
20888
20889                cx.emit(EditorEvent::BufferEdited);
20890                cx.emit(SearchEvent::MatchesInvalidated);
20891
20892                let Some(project) = &self.project else { return };
20893                let (telemetry, is_via_ssh) = {
20894                    let project = project.read(cx);
20895                    let telemetry = project.client().telemetry().clone();
20896                    let is_via_ssh = project.is_via_remote_server();
20897                    (telemetry, is_via_ssh)
20898                };
20899                telemetry.log_edit_event("editor", is_via_ssh);
20900            }
20901            multi_buffer::Event::ExcerptsAdded {
20902                buffer,
20903                predecessor,
20904                excerpts,
20905            } => {
20906                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20907                let buffer_id = buffer.read(cx).remote_id();
20908                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20909                    && let Some(project) = &self.project
20910                {
20911                    update_uncommitted_diff_for_buffer(
20912                        cx.entity(),
20913                        project,
20914                        [buffer.clone()],
20915                        self.buffer.clone(),
20916                        cx,
20917                    )
20918                    .detach();
20919                }
20920                self.update_lsp_data(Some(buffer_id), window, cx);
20921                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20922                cx.emit(EditorEvent::ExcerptsAdded {
20923                    buffer: buffer.clone(),
20924                    predecessor: *predecessor,
20925                    excerpts: excerpts.clone(),
20926                });
20927            }
20928            multi_buffer::Event::ExcerptsRemoved {
20929                ids,
20930                removed_buffer_ids,
20931            } => {
20932                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20933                for buffer_id in removed_buffer_ids {
20934                    self.registered_buffers.remove(buffer_id);
20935                }
20936                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20937                cx.emit(EditorEvent::ExcerptsRemoved {
20938                    ids: ids.clone(),
20939                    removed_buffer_ids: removed_buffer_ids.clone(),
20940                });
20941            }
20942            multi_buffer::Event::ExcerptsEdited {
20943                excerpt_ids,
20944                buffer_ids,
20945            } => {
20946                self.display_map.update(cx, |map, cx| {
20947                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20948                });
20949                cx.emit(EditorEvent::ExcerptsEdited {
20950                    ids: excerpt_ids.clone(),
20951                });
20952            }
20953            multi_buffer::Event::ExcerptsExpanded { ids } => {
20954                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20955                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20956            }
20957            multi_buffer::Event::Reparsed(buffer_id) => {
20958                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20959                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20960
20961                cx.emit(EditorEvent::Reparsed(*buffer_id));
20962            }
20963            multi_buffer::Event::DiffHunksToggled => {
20964                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20965            }
20966            multi_buffer::Event::LanguageChanged(buffer_id) => {
20967                self.registered_buffers.remove(&buffer_id);
20968                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20969                cx.emit(EditorEvent::Reparsed(*buffer_id));
20970                cx.notify();
20971            }
20972            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20973            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20974            multi_buffer::Event::FileHandleChanged
20975            | multi_buffer::Event::Reloaded
20976            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20977            multi_buffer::Event::DiagnosticsUpdated => {
20978                self.update_diagnostics_state(window, cx);
20979            }
20980            _ => {}
20981        };
20982    }
20983
20984    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20985        if !self.diagnostics_enabled() {
20986            return;
20987        }
20988        self.refresh_active_diagnostics(cx);
20989        self.refresh_inline_diagnostics(true, window, cx);
20990        self.scrollbar_marker_state.dirty = true;
20991        cx.notify();
20992    }
20993
20994    pub fn start_temporary_diff_override(&mut self) {
20995        self.load_diff_task.take();
20996        self.temporary_diff_override = true;
20997    }
20998
20999    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21000        self.temporary_diff_override = false;
21001        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21002        self.buffer.update(cx, |buffer, cx| {
21003            buffer.set_all_diff_hunks_collapsed(cx);
21004        });
21005
21006        if let Some(project) = self.project.clone() {
21007            self.load_diff_task = Some(
21008                update_uncommitted_diff_for_buffer(
21009                    cx.entity(),
21010                    &project,
21011                    self.buffer.read(cx).all_buffers(),
21012                    self.buffer.clone(),
21013                    cx,
21014                )
21015                .shared(),
21016            );
21017        }
21018    }
21019
21020    fn on_display_map_changed(
21021        &mut self,
21022        _: Entity<DisplayMap>,
21023        _: &mut Window,
21024        cx: &mut Context<Self>,
21025    ) {
21026        cx.notify();
21027    }
21028
21029    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21030        if self.diagnostics_enabled() {
21031            let new_severity = EditorSettings::get_global(cx)
21032                .diagnostics_max_severity
21033                .unwrap_or(DiagnosticSeverity::Hint);
21034            self.set_max_diagnostics_severity(new_severity, cx);
21035        }
21036        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21037        self.update_edit_prediction_settings(cx);
21038        self.refresh_edit_prediction(true, false, window, cx);
21039        self.refresh_inline_values(cx);
21040        self.refresh_inlay_hints(
21041            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21042                self.selections.newest_anchor().head(),
21043                &self.buffer.read(cx).snapshot(cx),
21044                cx,
21045            )),
21046            cx,
21047        );
21048
21049        let old_cursor_shape = self.cursor_shape;
21050        let old_show_breadcrumbs = self.show_breadcrumbs;
21051
21052        {
21053            let editor_settings = EditorSettings::get_global(cx);
21054            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21055            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21056            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21057            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21058        }
21059
21060        if old_cursor_shape != self.cursor_shape {
21061            cx.emit(EditorEvent::CursorShapeChanged);
21062        }
21063
21064        if old_show_breadcrumbs != self.show_breadcrumbs {
21065            cx.emit(EditorEvent::BreadcrumbsChanged);
21066        }
21067
21068        let project_settings = ProjectSettings::get_global(cx);
21069        self.serialize_dirty_buffers =
21070            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21071
21072        if self.mode.is_full() {
21073            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21074            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21075            if self.show_inline_diagnostics != show_inline_diagnostics {
21076                self.show_inline_diagnostics = show_inline_diagnostics;
21077                self.refresh_inline_diagnostics(false, window, cx);
21078            }
21079
21080            if self.git_blame_inline_enabled != inline_blame_enabled {
21081                self.toggle_git_blame_inline_internal(false, window, cx);
21082            }
21083
21084            let minimap_settings = EditorSettings::get_global(cx).minimap;
21085            if self.minimap_visibility != MinimapVisibility::Disabled {
21086                if self.minimap_visibility.settings_visibility()
21087                    != minimap_settings.minimap_enabled()
21088                {
21089                    self.set_minimap_visibility(
21090                        MinimapVisibility::for_mode(self.mode(), cx),
21091                        window,
21092                        cx,
21093                    );
21094                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21095                    minimap_entity.update(cx, |minimap_editor, cx| {
21096                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21097                    })
21098                }
21099            }
21100        }
21101
21102        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21103            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21104        }) {
21105            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21106                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21107            }
21108            self.refresh_colors_for_visible_range(None, window, cx);
21109        }
21110
21111        cx.notify();
21112    }
21113
21114    pub fn set_searchable(&mut self, searchable: bool) {
21115        self.searchable = searchable;
21116    }
21117
21118    pub fn searchable(&self) -> bool {
21119        self.searchable
21120    }
21121
21122    fn open_proposed_changes_editor(
21123        &mut self,
21124        _: &OpenProposedChangesEditor,
21125        window: &mut Window,
21126        cx: &mut Context<Self>,
21127    ) {
21128        let Some(workspace) = self.workspace() else {
21129            cx.propagate();
21130            return;
21131        };
21132
21133        let selections = self.selections.all::<usize>(cx);
21134        let multi_buffer = self.buffer.read(cx);
21135        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21136        let mut new_selections_by_buffer = HashMap::default();
21137        for selection in selections {
21138            for (buffer, range, _) in
21139                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21140            {
21141                let mut range = range.to_point(buffer);
21142                range.start.column = 0;
21143                range.end.column = buffer.line_len(range.end.row);
21144                new_selections_by_buffer
21145                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21146                    .or_insert(Vec::new())
21147                    .push(range)
21148            }
21149        }
21150
21151        let proposed_changes_buffers = new_selections_by_buffer
21152            .into_iter()
21153            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21154            .collect::<Vec<_>>();
21155        let proposed_changes_editor = cx.new(|cx| {
21156            ProposedChangesEditor::new(
21157                "Proposed changes",
21158                proposed_changes_buffers,
21159                self.project.clone(),
21160                window,
21161                cx,
21162            )
21163        });
21164
21165        window.defer(cx, move |window, cx| {
21166            workspace.update(cx, |workspace, cx| {
21167                workspace.active_pane().update(cx, |pane, cx| {
21168                    pane.add_item(
21169                        Box::new(proposed_changes_editor),
21170                        true,
21171                        true,
21172                        None,
21173                        window,
21174                        cx,
21175                    );
21176                });
21177            });
21178        });
21179    }
21180
21181    pub fn open_excerpts_in_split(
21182        &mut self,
21183        _: &OpenExcerptsSplit,
21184        window: &mut Window,
21185        cx: &mut Context<Self>,
21186    ) {
21187        self.open_excerpts_common(None, true, window, cx)
21188    }
21189
21190    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21191        self.open_excerpts_common(None, false, window, cx)
21192    }
21193
21194    fn open_excerpts_common(
21195        &mut self,
21196        jump_data: Option<JumpData>,
21197        split: bool,
21198        window: &mut Window,
21199        cx: &mut Context<Self>,
21200    ) {
21201        let Some(workspace) = self.workspace() else {
21202            cx.propagate();
21203            return;
21204        };
21205
21206        if self.buffer.read(cx).is_singleton() {
21207            cx.propagate();
21208            return;
21209        }
21210
21211        let mut new_selections_by_buffer = HashMap::default();
21212        match &jump_data {
21213            Some(JumpData::MultiBufferPoint {
21214                excerpt_id,
21215                position,
21216                anchor,
21217                line_offset_from_top,
21218            }) => {
21219                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21220                if let Some(buffer) = multi_buffer_snapshot
21221                    .buffer_id_for_excerpt(*excerpt_id)
21222                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21223                {
21224                    let buffer_snapshot = buffer.read(cx).snapshot();
21225                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21226                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21227                    } else {
21228                        buffer_snapshot.clip_point(*position, Bias::Left)
21229                    };
21230                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21231                    new_selections_by_buffer.insert(
21232                        buffer,
21233                        (
21234                            vec![jump_to_offset..jump_to_offset],
21235                            Some(*line_offset_from_top),
21236                        ),
21237                    );
21238                }
21239            }
21240            Some(JumpData::MultiBufferRow {
21241                row,
21242                line_offset_from_top,
21243            }) => {
21244                let point = MultiBufferPoint::new(row.0, 0);
21245                if let Some((buffer, buffer_point, _)) =
21246                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21247                {
21248                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21249                    new_selections_by_buffer
21250                        .entry(buffer)
21251                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21252                        .0
21253                        .push(buffer_offset..buffer_offset)
21254                }
21255            }
21256            None => {
21257                let selections = self.selections.all::<usize>(cx);
21258                let multi_buffer = self.buffer.read(cx);
21259                for selection in selections {
21260                    for (snapshot, range, _, anchor) in multi_buffer
21261                        .snapshot(cx)
21262                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21263                    {
21264                        if let Some(anchor) = anchor {
21265                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21266                            else {
21267                                continue;
21268                            };
21269                            let offset = text::ToOffset::to_offset(
21270                                &anchor.text_anchor,
21271                                &buffer_handle.read(cx).snapshot(),
21272                            );
21273                            let range = offset..offset;
21274                            new_selections_by_buffer
21275                                .entry(buffer_handle)
21276                                .or_insert((Vec::new(), None))
21277                                .0
21278                                .push(range)
21279                        } else {
21280                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21281                            else {
21282                                continue;
21283                            };
21284                            new_selections_by_buffer
21285                                .entry(buffer_handle)
21286                                .or_insert((Vec::new(), None))
21287                                .0
21288                                .push(range)
21289                        }
21290                    }
21291                }
21292            }
21293        }
21294
21295        new_selections_by_buffer
21296            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21297
21298        if new_selections_by_buffer.is_empty() {
21299            return;
21300        }
21301
21302        // We defer the pane interaction because we ourselves are a workspace item
21303        // and activating a new item causes the pane to call a method on us reentrantly,
21304        // which panics if we're on the stack.
21305        window.defer(cx, move |window, cx| {
21306            workspace.update(cx, |workspace, cx| {
21307                let pane = if split {
21308                    workspace.adjacent_pane(window, cx)
21309                } else {
21310                    workspace.active_pane().clone()
21311                };
21312
21313                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21314                    let editor = buffer
21315                        .read(cx)
21316                        .file()
21317                        .is_none()
21318                        .then(|| {
21319                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21320                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21321                            // Instead, we try to activate the existing editor in the pane first.
21322                            let (editor, pane_item_index) =
21323                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21324                                    let editor = item.downcast::<Editor>()?;
21325                                    let singleton_buffer =
21326                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21327                                    if singleton_buffer == buffer {
21328                                        Some((editor, i))
21329                                    } else {
21330                                        None
21331                                    }
21332                                })?;
21333                            pane.update(cx, |pane, cx| {
21334                                pane.activate_item(pane_item_index, true, true, window, cx)
21335                            });
21336                            Some(editor)
21337                        })
21338                        .flatten()
21339                        .unwrap_or_else(|| {
21340                            workspace.open_project_item::<Self>(
21341                                pane.clone(),
21342                                buffer,
21343                                true,
21344                                true,
21345                                window,
21346                                cx,
21347                            )
21348                        });
21349
21350                    editor.update(cx, |editor, cx| {
21351                        let autoscroll = match scroll_offset {
21352                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21353                            None => Autoscroll::newest(),
21354                        };
21355                        let nav_history = editor.nav_history.take();
21356                        editor.change_selections(
21357                            SelectionEffects::scroll(autoscroll),
21358                            window,
21359                            cx,
21360                            |s| {
21361                                s.select_ranges(ranges);
21362                            },
21363                        );
21364                        editor.nav_history = nav_history;
21365                    });
21366                }
21367            })
21368        });
21369    }
21370
21371    // For now, don't allow opening excerpts in buffers that aren't backed by
21372    // regular project files.
21373    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21374        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21375    }
21376
21377    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21378        let snapshot = self.buffer.read(cx).read(cx);
21379        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21380        Some(
21381            ranges
21382                .iter()
21383                .map(move |range| {
21384                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21385                })
21386                .collect(),
21387        )
21388    }
21389
21390    fn selection_replacement_ranges(
21391        &self,
21392        range: Range<OffsetUtf16>,
21393        cx: &mut App,
21394    ) -> Vec<Range<OffsetUtf16>> {
21395        let selections = self.selections.all::<OffsetUtf16>(cx);
21396        let newest_selection = selections
21397            .iter()
21398            .max_by_key(|selection| selection.id)
21399            .unwrap();
21400        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21401        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21402        let snapshot = self.buffer.read(cx).read(cx);
21403        selections
21404            .into_iter()
21405            .map(|mut selection| {
21406                selection.start.0 =
21407                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21408                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21409                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21410                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21411            })
21412            .collect()
21413    }
21414
21415    fn report_editor_event(
21416        &self,
21417        reported_event: ReportEditorEvent,
21418        file_extension: Option<String>,
21419        cx: &App,
21420    ) {
21421        if cfg!(any(test, feature = "test-support")) {
21422            return;
21423        }
21424
21425        let Some(project) = &self.project else { return };
21426
21427        // If None, we are in a file without an extension
21428        let file = self
21429            .buffer
21430            .read(cx)
21431            .as_singleton()
21432            .and_then(|b| b.read(cx).file());
21433        let file_extension = file_extension.or(file
21434            .as_ref()
21435            .and_then(|file| Path::new(file.file_name(cx)).extension())
21436            .and_then(|e| e.to_str())
21437            .map(|a| a.to_string()));
21438
21439        let vim_mode = vim_enabled(cx);
21440
21441        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21442        let copilot_enabled = edit_predictions_provider
21443            == language::language_settings::EditPredictionProvider::Copilot;
21444        let copilot_enabled_for_language = self
21445            .buffer
21446            .read(cx)
21447            .language_settings(cx)
21448            .show_edit_predictions;
21449
21450        let project = project.read(cx);
21451        let event_type = reported_event.event_type();
21452
21453        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21454            telemetry::event!(
21455                event_type,
21456                type = if auto_saved {"autosave"} else {"manual"},
21457                file_extension,
21458                vim_mode,
21459                copilot_enabled,
21460                copilot_enabled_for_language,
21461                edit_predictions_provider,
21462                is_via_ssh = project.is_via_remote_server(),
21463            );
21464        } else {
21465            telemetry::event!(
21466                event_type,
21467                file_extension,
21468                vim_mode,
21469                copilot_enabled,
21470                copilot_enabled_for_language,
21471                edit_predictions_provider,
21472                is_via_ssh = project.is_via_remote_server(),
21473            );
21474        };
21475    }
21476
21477    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21478    /// with each line being an array of {text, highlight} objects.
21479    fn copy_highlight_json(
21480        &mut self,
21481        _: &CopyHighlightJson,
21482        window: &mut Window,
21483        cx: &mut Context<Self>,
21484    ) {
21485        #[derive(Serialize)]
21486        struct Chunk<'a> {
21487            text: String,
21488            highlight: Option<&'a str>,
21489        }
21490
21491        let snapshot = self.buffer.read(cx).snapshot(cx);
21492        let range = self
21493            .selected_text_range(false, window, cx)
21494            .and_then(|selection| {
21495                if selection.range.is_empty() {
21496                    None
21497                } else {
21498                    Some(selection.range)
21499                }
21500            })
21501            .unwrap_or_else(|| 0..snapshot.len());
21502
21503        let chunks = snapshot.chunks(range, true);
21504        let mut lines = Vec::new();
21505        let mut line: VecDeque<Chunk> = VecDeque::new();
21506
21507        let Some(style) = self.style.as_ref() else {
21508            return;
21509        };
21510
21511        for chunk in chunks {
21512            let highlight = chunk
21513                .syntax_highlight_id
21514                .and_then(|id| id.name(&style.syntax));
21515            let mut chunk_lines = chunk.text.split('\n').peekable();
21516            while let Some(text) = chunk_lines.next() {
21517                let mut merged_with_last_token = false;
21518                if let Some(last_token) = line.back_mut()
21519                    && last_token.highlight == highlight
21520                {
21521                    last_token.text.push_str(text);
21522                    merged_with_last_token = true;
21523                }
21524
21525                if !merged_with_last_token {
21526                    line.push_back(Chunk {
21527                        text: text.into(),
21528                        highlight,
21529                    });
21530                }
21531
21532                if chunk_lines.peek().is_some() {
21533                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21534                        line.pop_front();
21535                    }
21536                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21537                        line.pop_back();
21538                    }
21539
21540                    lines.push(mem::take(&mut line));
21541                }
21542            }
21543        }
21544
21545        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21546            return;
21547        };
21548        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21549    }
21550
21551    pub fn open_context_menu(
21552        &mut self,
21553        _: &OpenContextMenu,
21554        window: &mut Window,
21555        cx: &mut Context<Self>,
21556    ) {
21557        self.request_autoscroll(Autoscroll::newest(), cx);
21558        let position = self.selections.newest_display(cx).start;
21559        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21560    }
21561
21562    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21563        &self.inlay_hint_cache
21564    }
21565
21566    pub fn replay_insert_event(
21567        &mut self,
21568        text: &str,
21569        relative_utf16_range: Option<Range<isize>>,
21570        window: &mut Window,
21571        cx: &mut Context<Self>,
21572    ) {
21573        if !self.input_enabled {
21574            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21575            return;
21576        }
21577        if let Some(relative_utf16_range) = relative_utf16_range {
21578            let selections = self.selections.all::<OffsetUtf16>(cx);
21579            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21580                let new_ranges = selections.into_iter().map(|range| {
21581                    let start = OffsetUtf16(
21582                        range
21583                            .head()
21584                            .0
21585                            .saturating_add_signed(relative_utf16_range.start),
21586                    );
21587                    let end = OffsetUtf16(
21588                        range
21589                            .head()
21590                            .0
21591                            .saturating_add_signed(relative_utf16_range.end),
21592                    );
21593                    start..end
21594                });
21595                s.select_ranges(new_ranges);
21596            });
21597        }
21598
21599        self.handle_input(text, window, cx);
21600    }
21601
21602    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21603        let Some(provider) = self.semantics_provider.as_ref() else {
21604            return false;
21605        };
21606
21607        let mut supports = false;
21608        self.buffer().update(cx, |this, cx| {
21609            this.for_each_buffer(|buffer| {
21610                supports |= provider.supports_inlay_hints(buffer, cx);
21611            });
21612        });
21613
21614        supports
21615    }
21616
21617    pub fn is_focused(&self, window: &Window) -> bool {
21618        self.focus_handle.is_focused(window)
21619    }
21620
21621    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21622        cx.emit(EditorEvent::Focused);
21623
21624        if let Some(descendant) = self
21625            .last_focused_descendant
21626            .take()
21627            .and_then(|descendant| descendant.upgrade())
21628        {
21629            window.focus(&descendant);
21630        } else {
21631            if let Some(blame) = self.blame.as_ref() {
21632                blame.update(cx, GitBlame::focus)
21633            }
21634
21635            self.blink_manager.update(cx, BlinkManager::enable);
21636            self.show_cursor_names(window, cx);
21637            self.buffer.update(cx, |buffer, cx| {
21638                buffer.finalize_last_transaction(cx);
21639                if self.leader_id.is_none() {
21640                    buffer.set_active_selections(
21641                        &self.selections.disjoint_anchors_arc(),
21642                        self.selections.line_mode(),
21643                        self.cursor_shape,
21644                        cx,
21645                    );
21646                }
21647            });
21648        }
21649    }
21650
21651    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21652        cx.emit(EditorEvent::FocusedIn)
21653    }
21654
21655    fn handle_focus_out(
21656        &mut self,
21657        event: FocusOutEvent,
21658        _window: &mut Window,
21659        cx: &mut Context<Self>,
21660    ) {
21661        if event.blurred != self.focus_handle {
21662            self.last_focused_descendant = Some(event.blurred);
21663        }
21664        self.selection_drag_state = SelectionDragState::None;
21665        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21666    }
21667
21668    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21669        self.blink_manager.update(cx, BlinkManager::disable);
21670        self.buffer
21671            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21672
21673        if let Some(blame) = self.blame.as_ref() {
21674            blame.update(cx, GitBlame::blur)
21675        }
21676        if !self.hover_state.focused(window, cx) {
21677            hide_hover(self, cx);
21678        }
21679        if !self
21680            .context_menu
21681            .borrow()
21682            .as_ref()
21683            .is_some_and(|context_menu| context_menu.focused(window, cx))
21684        {
21685            self.hide_context_menu(window, cx);
21686        }
21687        self.take_active_edit_prediction(cx);
21688        cx.emit(EditorEvent::Blurred);
21689        cx.notify();
21690    }
21691
21692    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21693        let mut pending: String = window
21694            .pending_input_keystrokes()
21695            .into_iter()
21696            .flatten()
21697            .filter_map(|keystroke| {
21698                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21699                    keystroke.key_char.clone()
21700                } else {
21701                    None
21702                }
21703            })
21704            .collect();
21705
21706        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21707            pending = "".to_string();
21708        }
21709
21710        let existing_pending = self
21711            .text_highlights::<PendingInput>(cx)
21712            .map(|(_, ranges)| ranges.to_vec());
21713        if existing_pending.is_none() && pending.is_empty() {
21714            return;
21715        }
21716        let transaction =
21717            self.transact(window, cx, |this, window, cx| {
21718                let selections = this.selections.all::<usize>(cx);
21719                let edits = selections
21720                    .iter()
21721                    .map(|selection| (selection.end..selection.end, pending.clone()));
21722                this.edit(edits, cx);
21723                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21724                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21725                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21726                    }));
21727                });
21728                if let Some(existing_ranges) = existing_pending {
21729                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21730                    this.edit(edits, cx);
21731                }
21732            });
21733
21734        let snapshot = self.snapshot(window, cx);
21735        let ranges = self
21736            .selections
21737            .all::<usize>(cx)
21738            .into_iter()
21739            .map(|selection| {
21740                snapshot.buffer_snapshot().anchor_after(selection.end)
21741                    ..snapshot
21742                        .buffer_snapshot()
21743                        .anchor_before(selection.end + pending.len())
21744            })
21745            .collect();
21746
21747        if pending.is_empty() {
21748            self.clear_highlights::<PendingInput>(cx);
21749        } else {
21750            self.highlight_text::<PendingInput>(
21751                ranges,
21752                HighlightStyle {
21753                    underline: Some(UnderlineStyle {
21754                        thickness: px(1.),
21755                        color: None,
21756                        wavy: false,
21757                    }),
21758                    ..Default::default()
21759                },
21760                cx,
21761            );
21762        }
21763
21764        self.ime_transaction = self.ime_transaction.or(transaction);
21765        if let Some(transaction) = self.ime_transaction {
21766            self.buffer.update(cx, |buffer, cx| {
21767                buffer.group_until_transaction(transaction, cx);
21768            });
21769        }
21770
21771        if self.text_highlights::<PendingInput>(cx).is_none() {
21772            self.ime_transaction.take();
21773        }
21774    }
21775
21776    pub fn register_action_renderer(
21777        &mut self,
21778        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21779    ) -> Subscription {
21780        let id = self.next_editor_action_id.post_inc();
21781        self.editor_actions
21782            .borrow_mut()
21783            .insert(id, Box::new(listener));
21784
21785        let editor_actions = self.editor_actions.clone();
21786        Subscription::new(move || {
21787            editor_actions.borrow_mut().remove(&id);
21788        })
21789    }
21790
21791    pub fn register_action<A: Action>(
21792        &mut self,
21793        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21794    ) -> Subscription {
21795        let id = self.next_editor_action_id.post_inc();
21796        let listener = Arc::new(listener);
21797        self.editor_actions.borrow_mut().insert(
21798            id,
21799            Box::new(move |_, window, _| {
21800                let listener = listener.clone();
21801                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21802                    let action = action.downcast_ref().unwrap();
21803                    if phase == DispatchPhase::Bubble {
21804                        listener(action, window, cx)
21805                    }
21806                })
21807            }),
21808        );
21809
21810        let editor_actions = self.editor_actions.clone();
21811        Subscription::new(move || {
21812            editor_actions.borrow_mut().remove(&id);
21813        })
21814    }
21815
21816    pub fn file_header_size(&self) -> u32 {
21817        FILE_HEADER_HEIGHT
21818    }
21819
21820    pub fn restore(
21821        &mut self,
21822        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21823        window: &mut Window,
21824        cx: &mut Context<Self>,
21825    ) {
21826        let workspace = self.workspace();
21827        let project = self.project();
21828        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21829            let mut tasks = Vec::new();
21830            for (buffer_id, changes) in revert_changes {
21831                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21832                    buffer.update(cx, |buffer, cx| {
21833                        buffer.edit(
21834                            changes
21835                                .into_iter()
21836                                .map(|(range, text)| (range, text.to_string())),
21837                            None,
21838                            cx,
21839                        );
21840                    });
21841
21842                    if let Some(project) =
21843                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21844                    {
21845                        project.update(cx, |project, cx| {
21846                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21847                        })
21848                    }
21849                }
21850            }
21851            tasks
21852        });
21853        cx.spawn_in(window, async move |_, cx| {
21854            for (buffer, task) in save_tasks {
21855                let result = task.await;
21856                if result.is_err() {
21857                    let Some(path) = buffer
21858                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21859                        .ok()
21860                    else {
21861                        continue;
21862                    };
21863                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21864                        let Some(task) = cx
21865                            .update_window_entity(workspace, |workspace, window, cx| {
21866                                workspace
21867                                    .open_path_preview(path, None, false, false, false, window, cx)
21868                            })
21869                            .ok()
21870                        else {
21871                            continue;
21872                        };
21873                        task.await.log_err();
21874                    }
21875                }
21876            }
21877        })
21878        .detach();
21879        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21880            selections.refresh()
21881        });
21882    }
21883
21884    pub fn to_pixel_point(
21885        &self,
21886        source: multi_buffer::Anchor,
21887        editor_snapshot: &EditorSnapshot,
21888        window: &mut Window,
21889    ) -> Option<gpui::Point<Pixels>> {
21890        let source_point = source.to_display_point(editor_snapshot);
21891        self.display_to_pixel_point(source_point, editor_snapshot, window)
21892    }
21893
21894    pub fn display_to_pixel_point(
21895        &self,
21896        source: DisplayPoint,
21897        editor_snapshot: &EditorSnapshot,
21898        window: &mut Window,
21899    ) -> Option<gpui::Point<Pixels>> {
21900        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21901        let text_layout_details = self.text_layout_details(window);
21902        let scroll_top = text_layout_details
21903            .scroll_anchor
21904            .scroll_position(editor_snapshot)
21905            .y;
21906
21907        if source.row().as_f64() < scroll_top.floor() {
21908            return None;
21909        }
21910        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21911        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21912        Some(gpui::Point::new(source_x, source_y))
21913    }
21914
21915    pub fn has_visible_completions_menu(&self) -> bool {
21916        !self.edit_prediction_preview_is_active()
21917            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21918                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21919            })
21920    }
21921
21922    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21923        if self.mode.is_minimap() {
21924            return;
21925        }
21926        self.addons
21927            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21928    }
21929
21930    pub fn unregister_addon<T: Addon>(&mut self) {
21931        self.addons.remove(&std::any::TypeId::of::<T>());
21932    }
21933
21934    pub fn addon<T: Addon>(&self) -> Option<&T> {
21935        let type_id = std::any::TypeId::of::<T>();
21936        self.addons
21937            .get(&type_id)
21938            .and_then(|item| item.to_any().downcast_ref::<T>())
21939    }
21940
21941    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21942        let type_id = std::any::TypeId::of::<T>();
21943        self.addons
21944            .get_mut(&type_id)
21945            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21946    }
21947
21948    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21949        let text_layout_details = self.text_layout_details(window);
21950        let style = &text_layout_details.editor_style;
21951        let font_id = window.text_system().resolve_font(&style.text.font());
21952        let font_size = style.text.font_size.to_pixels(window.rem_size());
21953        let line_height = style.text.line_height_in_pixels(window.rem_size());
21954        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21955        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21956
21957        CharacterDimensions {
21958            em_width,
21959            em_advance,
21960            line_height,
21961        }
21962    }
21963
21964    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21965        self.load_diff_task.clone()
21966    }
21967
21968    fn read_metadata_from_db(
21969        &mut self,
21970        item_id: u64,
21971        workspace_id: WorkspaceId,
21972        window: &mut Window,
21973        cx: &mut Context<Editor>,
21974    ) {
21975        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21976            && !self.mode.is_minimap()
21977            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21978        {
21979            let buffer_snapshot = OnceCell::new();
21980
21981            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21982                && !folds.is_empty()
21983            {
21984                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21985                self.fold_ranges(
21986                    folds
21987                        .into_iter()
21988                        .map(|(start, end)| {
21989                            snapshot.clip_offset(start, Bias::Left)
21990                                ..snapshot.clip_offset(end, Bias::Right)
21991                        })
21992                        .collect(),
21993                    false,
21994                    window,
21995                    cx,
21996                );
21997            }
21998
21999            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22000                && !selections.is_empty()
22001            {
22002                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22003                // skip adding the initial selection to selection history
22004                self.selection_history.mode = SelectionHistoryMode::Skipping;
22005                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22006                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22007                        snapshot.clip_offset(start, Bias::Left)
22008                            ..snapshot.clip_offset(end, Bias::Right)
22009                    }));
22010                });
22011                self.selection_history.mode = SelectionHistoryMode::Normal;
22012            };
22013        }
22014
22015        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22016    }
22017
22018    fn update_lsp_data(
22019        &mut self,
22020        for_buffer: Option<BufferId>,
22021        window: &mut Window,
22022        cx: &mut Context<'_, Self>,
22023    ) {
22024        self.pull_diagnostics(for_buffer, window, cx);
22025        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22026    }
22027
22028    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22029        // Singletons are registered on editor creation.
22030        if self.ignore_lsp_data() || self.buffer().read(cx).is_singleton() {
22031            return;
22032        }
22033        for (_, (visible_buffer, _, _)) in self.visible_excerpts(None, cx) {
22034            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22035        }
22036    }
22037
22038    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) -> bool {
22039        if !self.registered_buffers.contains_key(&buffer_id)
22040            && let Some(project) = self.project.as_ref()
22041        {
22042            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22043                project.update(cx, |project, cx| {
22044                    self.registered_buffers.insert(
22045                        buffer_id,
22046                        project.register_buffer_with_language_servers(&buffer, cx),
22047                    );
22048                });
22049                return true;
22050            } else {
22051                self.registered_buffers.remove(&buffer_id);
22052            }
22053        }
22054
22055        false
22056    }
22057
22058    fn ignore_lsp_data(&self) -> bool {
22059        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22060        // skip any LSP updates for it.
22061        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22062    }
22063}
22064
22065fn edit_for_markdown_paste<'a>(
22066    buffer: &MultiBufferSnapshot,
22067    range: Range<usize>,
22068    to_insert: &'a str,
22069    url: Option<url::Url>,
22070) -> (Range<usize>, Cow<'a, str>) {
22071    if url.is_none() {
22072        return (range, Cow::Borrowed(to_insert));
22073    };
22074
22075    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22076
22077    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22078        Cow::Borrowed(to_insert)
22079    } else {
22080        Cow::Owned(format!("[{old_text}]({to_insert})"))
22081    };
22082    (range, new_text)
22083}
22084
22085fn vim_enabled(cx: &App) -> bool {
22086    vim_mode_setting::VimModeSetting::try_get(cx)
22087        .map(|vim_mode| vim_mode.0)
22088        .unwrap_or(false)
22089}
22090
22091fn process_completion_for_edit(
22092    completion: &Completion,
22093    intent: CompletionIntent,
22094    buffer: &Entity<Buffer>,
22095    cursor_position: &text::Anchor,
22096    cx: &mut Context<Editor>,
22097) -> CompletionEdit {
22098    let buffer = buffer.read(cx);
22099    let buffer_snapshot = buffer.snapshot();
22100    let (snippet, new_text) = if completion.is_snippet() {
22101        let mut snippet_source = completion.new_text.clone();
22102        // Workaround for typescript language server issues so that methods don't expand within
22103        // strings and functions with type expressions. The previous point is used because the query
22104        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22105        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22106        let previous_point = if previous_point.column > 0 {
22107            cursor_position.to_previous_offset(&buffer_snapshot)
22108        } else {
22109            cursor_position.to_offset(&buffer_snapshot)
22110        };
22111        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22112            && scope.prefers_label_for_snippet_in_completion()
22113            && let Some(label) = completion.label()
22114            && matches!(
22115                completion.kind(),
22116                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22117            )
22118        {
22119            snippet_source = label;
22120        }
22121        match Snippet::parse(&snippet_source).log_err() {
22122            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22123            None => (None, completion.new_text.clone()),
22124        }
22125    } else {
22126        (None, completion.new_text.clone())
22127    };
22128
22129    let mut range_to_replace = {
22130        let replace_range = &completion.replace_range;
22131        if let CompletionSource::Lsp {
22132            insert_range: Some(insert_range),
22133            ..
22134        } = &completion.source
22135        {
22136            debug_assert_eq!(
22137                insert_range.start, replace_range.start,
22138                "insert_range and replace_range should start at the same position"
22139            );
22140            debug_assert!(
22141                insert_range
22142                    .start
22143                    .cmp(cursor_position, &buffer_snapshot)
22144                    .is_le(),
22145                "insert_range should start before or at cursor position"
22146            );
22147            debug_assert!(
22148                replace_range
22149                    .start
22150                    .cmp(cursor_position, &buffer_snapshot)
22151                    .is_le(),
22152                "replace_range should start before or at cursor position"
22153            );
22154
22155            let should_replace = match intent {
22156                CompletionIntent::CompleteWithInsert => false,
22157                CompletionIntent::CompleteWithReplace => true,
22158                CompletionIntent::Complete | CompletionIntent::Compose => {
22159                    let insert_mode =
22160                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22161                            .completions
22162                            .lsp_insert_mode;
22163                    match insert_mode {
22164                        LspInsertMode::Insert => false,
22165                        LspInsertMode::Replace => true,
22166                        LspInsertMode::ReplaceSubsequence => {
22167                            let mut text_to_replace = buffer.chars_for_range(
22168                                buffer.anchor_before(replace_range.start)
22169                                    ..buffer.anchor_after(replace_range.end),
22170                            );
22171                            let mut current_needle = text_to_replace.next();
22172                            for haystack_ch in completion.label.text.chars() {
22173                                if let Some(needle_ch) = current_needle
22174                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22175                                {
22176                                    current_needle = text_to_replace.next();
22177                                }
22178                            }
22179                            current_needle.is_none()
22180                        }
22181                        LspInsertMode::ReplaceSuffix => {
22182                            if replace_range
22183                                .end
22184                                .cmp(cursor_position, &buffer_snapshot)
22185                                .is_gt()
22186                            {
22187                                let range_after_cursor = *cursor_position..replace_range.end;
22188                                let text_after_cursor = buffer
22189                                    .text_for_range(
22190                                        buffer.anchor_before(range_after_cursor.start)
22191                                            ..buffer.anchor_after(range_after_cursor.end),
22192                                    )
22193                                    .collect::<String>()
22194                                    .to_ascii_lowercase();
22195                                completion
22196                                    .label
22197                                    .text
22198                                    .to_ascii_lowercase()
22199                                    .ends_with(&text_after_cursor)
22200                            } else {
22201                                true
22202                            }
22203                        }
22204                    }
22205                }
22206            };
22207
22208            if should_replace {
22209                replace_range.clone()
22210            } else {
22211                insert_range.clone()
22212            }
22213        } else {
22214            replace_range.clone()
22215        }
22216    };
22217
22218    if range_to_replace
22219        .end
22220        .cmp(cursor_position, &buffer_snapshot)
22221        .is_lt()
22222    {
22223        range_to_replace.end = *cursor_position;
22224    }
22225
22226    CompletionEdit {
22227        new_text,
22228        replace_range: range_to_replace.to_offset(buffer),
22229        snippet,
22230    }
22231}
22232
22233struct CompletionEdit {
22234    new_text: String,
22235    replace_range: Range<usize>,
22236    snippet: Option<Snippet>,
22237}
22238
22239fn insert_extra_newline_brackets(
22240    buffer: &MultiBufferSnapshot,
22241    range: Range<usize>,
22242    language: &language::LanguageScope,
22243) -> bool {
22244    let leading_whitespace_len = buffer
22245        .reversed_chars_at(range.start)
22246        .take_while(|c| c.is_whitespace() && *c != '\n')
22247        .map(|c| c.len_utf8())
22248        .sum::<usize>();
22249    let trailing_whitespace_len = buffer
22250        .chars_at(range.end)
22251        .take_while(|c| c.is_whitespace() && *c != '\n')
22252        .map(|c| c.len_utf8())
22253        .sum::<usize>();
22254    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22255
22256    language.brackets().any(|(pair, enabled)| {
22257        let pair_start = pair.start.trim_end();
22258        let pair_end = pair.end.trim_start();
22259
22260        enabled
22261            && pair.newline
22262            && buffer.contains_str_at(range.end, pair_end)
22263            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22264    })
22265}
22266
22267fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22268    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22269        [(buffer, range, _)] => (*buffer, range.clone()),
22270        _ => return false,
22271    };
22272    let pair = {
22273        let mut result: Option<BracketMatch> = None;
22274
22275        for pair in buffer
22276            .all_bracket_ranges(range.clone())
22277            .filter(move |pair| {
22278                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22279            })
22280        {
22281            let len = pair.close_range.end - pair.open_range.start;
22282
22283            if let Some(existing) = &result {
22284                let existing_len = existing.close_range.end - existing.open_range.start;
22285                if len > existing_len {
22286                    continue;
22287                }
22288            }
22289
22290            result = Some(pair);
22291        }
22292
22293        result
22294    };
22295    let Some(pair) = pair else {
22296        return false;
22297    };
22298    pair.newline_only
22299        && buffer
22300            .chars_for_range(pair.open_range.end..range.start)
22301            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22302            .all(|c| c.is_whitespace() && c != '\n')
22303}
22304
22305fn update_uncommitted_diff_for_buffer(
22306    editor: Entity<Editor>,
22307    project: &Entity<Project>,
22308    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22309    buffer: Entity<MultiBuffer>,
22310    cx: &mut App,
22311) -> Task<()> {
22312    let mut tasks = Vec::new();
22313    project.update(cx, |project, cx| {
22314        for buffer in buffers {
22315            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22316                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22317            }
22318        }
22319    });
22320    cx.spawn(async move |cx| {
22321        let diffs = future::join_all(tasks).await;
22322        if editor
22323            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22324            .unwrap_or(false)
22325        {
22326            return;
22327        }
22328
22329        buffer
22330            .update(cx, |buffer, cx| {
22331                for diff in diffs.into_iter().flatten() {
22332                    buffer.add_diff(diff, cx);
22333                }
22334            })
22335            .ok();
22336    })
22337}
22338
22339fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22340    let tab_size = tab_size.get() as usize;
22341    let mut width = offset;
22342
22343    for ch in text.chars() {
22344        width += if ch == '\t' {
22345            tab_size - (width % tab_size)
22346        } else {
22347            1
22348        };
22349    }
22350
22351    width - offset
22352}
22353
22354#[cfg(test)]
22355mod tests {
22356    use super::*;
22357
22358    #[test]
22359    fn test_string_size_with_expanded_tabs() {
22360        let nz = |val| NonZeroU32::new(val).unwrap();
22361        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22362        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22363        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22364        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22365        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22366        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22367        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22368        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22369    }
22370}
22371
22372/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22373struct WordBreakingTokenizer<'a> {
22374    input: &'a str,
22375}
22376
22377impl<'a> WordBreakingTokenizer<'a> {
22378    fn new(input: &'a str) -> Self {
22379        Self { input }
22380    }
22381}
22382
22383fn is_char_ideographic(ch: char) -> bool {
22384    use unicode_script::Script::*;
22385    use unicode_script::UnicodeScript;
22386    matches!(ch.script(), Han | Tangut | Yi)
22387}
22388
22389fn is_grapheme_ideographic(text: &str) -> bool {
22390    text.chars().any(is_char_ideographic)
22391}
22392
22393fn is_grapheme_whitespace(text: &str) -> bool {
22394    text.chars().any(|x| x.is_whitespace())
22395}
22396
22397fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22398    text.chars()
22399        .next()
22400        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22401}
22402
22403#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22404enum WordBreakToken<'a> {
22405    Word { token: &'a str, grapheme_len: usize },
22406    InlineWhitespace { token: &'a str, grapheme_len: usize },
22407    Newline,
22408}
22409
22410impl<'a> Iterator for WordBreakingTokenizer<'a> {
22411    /// Yields a span, the count of graphemes in the token, and whether it was
22412    /// whitespace. Note that it also breaks at word boundaries.
22413    type Item = WordBreakToken<'a>;
22414
22415    fn next(&mut self) -> Option<Self::Item> {
22416        use unicode_segmentation::UnicodeSegmentation;
22417        if self.input.is_empty() {
22418            return None;
22419        }
22420
22421        let mut iter = self.input.graphemes(true).peekable();
22422        let mut offset = 0;
22423        let mut grapheme_len = 0;
22424        if let Some(first_grapheme) = iter.next() {
22425            let is_newline = first_grapheme == "\n";
22426            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22427            offset += first_grapheme.len();
22428            grapheme_len += 1;
22429            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22430                if let Some(grapheme) = iter.peek().copied()
22431                    && should_stay_with_preceding_ideograph(grapheme)
22432                {
22433                    offset += grapheme.len();
22434                    grapheme_len += 1;
22435                }
22436            } else {
22437                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22438                let mut next_word_bound = words.peek().copied();
22439                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22440                    next_word_bound = words.next();
22441                }
22442                while let Some(grapheme) = iter.peek().copied() {
22443                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22444                        break;
22445                    };
22446                    if is_grapheme_whitespace(grapheme) != is_whitespace
22447                        || (grapheme == "\n") != is_newline
22448                    {
22449                        break;
22450                    };
22451                    offset += grapheme.len();
22452                    grapheme_len += 1;
22453                    iter.next();
22454                }
22455            }
22456            let token = &self.input[..offset];
22457            self.input = &self.input[offset..];
22458            if token == "\n" {
22459                Some(WordBreakToken::Newline)
22460            } else if is_whitespace {
22461                Some(WordBreakToken::InlineWhitespace {
22462                    token,
22463                    grapheme_len,
22464                })
22465            } else {
22466                Some(WordBreakToken::Word {
22467                    token,
22468                    grapheme_len,
22469                })
22470            }
22471        } else {
22472            None
22473        }
22474    }
22475}
22476
22477#[test]
22478fn test_word_breaking_tokenizer() {
22479    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22480        ("", &[]),
22481        ("  ", &[whitespace("  ", 2)]),
22482        ("Ʒ", &[word("Ʒ", 1)]),
22483        ("Ǽ", &[word("Ǽ", 1)]),
22484        ("", &[word("", 1)]),
22485        ("⋑⋑", &[word("⋑⋑", 2)]),
22486        (
22487            "原理,进而",
22488            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22489        ),
22490        (
22491            "hello world",
22492            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22493        ),
22494        (
22495            "hello, world",
22496            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22497        ),
22498        (
22499            "  hello world",
22500            &[
22501                whitespace("  ", 2),
22502                word("hello", 5),
22503                whitespace(" ", 1),
22504                word("world", 5),
22505            ],
22506        ),
22507        (
22508            "这是什么 \n 钢笔",
22509            &[
22510                word("", 1),
22511                word("", 1),
22512                word("", 1),
22513                word("", 1),
22514                whitespace(" ", 1),
22515                newline(),
22516                whitespace(" ", 1),
22517                word("", 1),
22518                word("", 1),
22519            ],
22520        ),
22521        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22522    ];
22523
22524    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22525        WordBreakToken::Word {
22526            token,
22527            grapheme_len,
22528        }
22529    }
22530
22531    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22532        WordBreakToken::InlineWhitespace {
22533            token,
22534            grapheme_len,
22535        }
22536    }
22537
22538    fn newline() -> WordBreakToken<'static> {
22539        WordBreakToken::Newline
22540    }
22541
22542    for (input, result) in tests {
22543        assert_eq!(
22544            WordBreakingTokenizer::new(input)
22545                .collect::<Vec<_>>()
22546                .as_slice(),
22547            *result,
22548        );
22549    }
22550}
22551
22552fn wrap_with_prefix(
22553    first_line_prefix: String,
22554    subsequent_lines_prefix: String,
22555    unwrapped_text: String,
22556    wrap_column: usize,
22557    tab_size: NonZeroU32,
22558    preserve_existing_whitespace: bool,
22559) -> String {
22560    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22561    let subsequent_lines_prefix_len =
22562        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22563    let mut wrapped_text = String::new();
22564    let mut current_line = first_line_prefix;
22565    let mut is_first_line = true;
22566
22567    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22568    let mut current_line_len = first_line_prefix_len;
22569    let mut in_whitespace = false;
22570    for token in tokenizer {
22571        let have_preceding_whitespace = in_whitespace;
22572        match token {
22573            WordBreakToken::Word {
22574                token,
22575                grapheme_len,
22576            } => {
22577                in_whitespace = false;
22578                let current_prefix_len = if is_first_line {
22579                    first_line_prefix_len
22580                } else {
22581                    subsequent_lines_prefix_len
22582                };
22583                if current_line_len + grapheme_len > wrap_column
22584                    && current_line_len != current_prefix_len
22585                {
22586                    wrapped_text.push_str(current_line.trim_end());
22587                    wrapped_text.push('\n');
22588                    is_first_line = false;
22589                    current_line = subsequent_lines_prefix.clone();
22590                    current_line_len = subsequent_lines_prefix_len;
22591                }
22592                current_line.push_str(token);
22593                current_line_len += grapheme_len;
22594            }
22595            WordBreakToken::InlineWhitespace {
22596                mut token,
22597                mut grapheme_len,
22598            } => {
22599                in_whitespace = true;
22600                if have_preceding_whitespace && !preserve_existing_whitespace {
22601                    continue;
22602                }
22603                if !preserve_existing_whitespace {
22604                    // Keep a single whitespace grapheme as-is
22605                    if let Some(first) =
22606                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22607                    {
22608                        token = first;
22609                    } else {
22610                        token = " ";
22611                    }
22612                    grapheme_len = 1;
22613                }
22614                let current_prefix_len = if is_first_line {
22615                    first_line_prefix_len
22616                } else {
22617                    subsequent_lines_prefix_len
22618                };
22619                if current_line_len + grapheme_len > wrap_column {
22620                    wrapped_text.push_str(current_line.trim_end());
22621                    wrapped_text.push('\n');
22622                    is_first_line = false;
22623                    current_line = subsequent_lines_prefix.clone();
22624                    current_line_len = subsequent_lines_prefix_len;
22625                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22626                    current_line.push_str(token);
22627                    current_line_len += grapheme_len;
22628                }
22629            }
22630            WordBreakToken::Newline => {
22631                in_whitespace = true;
22632                let current_prefix_len = if is_first_line {
22633                    first_line_prefix_len
22634                } else {
22635                    subsequent_lines_prefix_len
22636                };
22637                if preserve_existing_whitespace {
22638                    wrapped_text.push_str(current_line.trim_end());
22639                    wrapped_text.push('\n');
22640                    is_first_line = false;
22641                    current_line = subsequent_lines_prefix.clone();
22642                    current_line_len = subsequent_lines_prefix_len;
22643                } else if have_preceding_whitespace {
22644                    continue;
22645                } else if current_line_len + 1 > wrap_column
22646                    && current_line_len != current_prefix_len
22647                {
22648                    wrapped_text.push_str(current_line.trim_end());
22649                    wrapped_text.push('\n');
22650                    is_first_line = false;
22651                    current_line = subsequent_lines_prefix.clone();
22652                    current_line_len = subsequent_lines_prefix_len;
22653                } else if current_line_len != current_prefix_len {
22654                    current_line.push(' ');
22655                    current_line_len += 1;
22656                }
22657            }
22658        }
22659    }
22660
22661    if !current_line.is_empty() {
22662        wrapped_text.push_str(&current_line);
22663    }
22664    wrapped_text
22665}
22666
22667#[test]
22668fn test_wrap_with_prefix() {
22669    assert_eq!(
22670        wrap_with_prefix(
22671            "# ".to_string(),
22672            "# ".to_string(),
22673            "abcdefg".to_string(),
22674            4,
22675            NonZeroU32::new(4).unwrap(),
22676            false,
22677        ),
22678        "# abcdefg"
22679    );
22680    assert_eq!(
22681        wrap_with_prefix(
22682            "".to_string(),
22683            "".to_string(),
22684            "\thello world".to_string(),
22685            8,
22686            NonZeroU32::new(4).unwrap(),
22687            false,
22688        ),
22689        "hello\nworld"
22690    );
22691    assert_eq!(
22692        wrap_with_prefix(
22693            "// ".to_string(),
22694            "// ".to_string(),
22695            "xx \nyy zz aa bb cc".to_string(),
22696            12,
22697            NonZeroU32::new(4).unwrap(),
22698            false,
22699        ),
22700        "// xx yy zz\n// aa bb cc"
22701    );
22702    assert_eq!(
22703        wrap_with_prefix(
22704            String::new(),
22705            String::new(),
22706            "这是什么 \n 钢笔".to_string(),
22707            3,
22708            NonZeroU32::new(4).unwrap(),
22709            false,
22710        ),
22711        "这是什\n么 钢\n"
22712    );
22713    assert_eq!(
22714        wrap_with_prefix(
22715            String::new(),
22716            String::new(),
22717            format!("foo{}bar", '\u{2009}'), // thin space
22718            80,
22719            NonZeroU32::new(4).unwrap(),
22720            false,
22721        ),
22722        format!("foo{}bar", '\u{2009}')
22723    );
22724}
22725
22726pub trait CollaborationHub {
22727    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22728    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22729    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22730}
22731
22732impl CollaborationHub for Entity<Project> {
22733    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22734        self.read(cx).collaborators()
22735    }
22736
22737    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22738        self.read(cx).user_store().read(cx).participant_indices()
22739    }
22740
22741    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22742        let this = self.read(cx);
22743        let user_ids = this.collaborators().values().map(|c| c.user_id);
22744        this.user_store().read(cx).participant_names(user_ids, cx)
22745    }
22746}
22747
22748pub trait SemanticsProvider {
22749    fn hover(
22750        &self,
22751        buffer: &Entity<Buffer>,
22752        position: text::Anchor,
22753        cx: &mut App,
22754    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22755
22756    fn inline_values(
22757        &self,
22758        buffer_handle: Entity<Buffer>,
22759        range: Range<text::Anchor>,
22760        cx: &mut App,
22761    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22762
22763    fn inlay_hints(
22764        &self,
22765        buffer_handle: Entity<Buffer>,
22766        range: Range<text::Anchor>,
22767        cx: &mut App,
22768    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22769
22770    fn resolve_inlay_hint(
22771        &self,
22772        hint: InlayHint,
22773        buffer_handle: Entity<Buffer>,
22774        server_id: LanguageServerId,
22775        cx: &mut App,
22776    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22777
22778    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22779
22780    fn document_highlights(
22781        &self,
22782        buffer: &Entity<Buffer>,
22783        position: text::Anchor,
22784        cx: &mut App,
22785    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22786
22787    fn definitions(
22788        &self,
22789        buffer: &Entity<Buffer>,
22790        position: text::Anchor,
22791        kind: GotoDefinitionKind,
22792        cx: &mut App,
22793    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22794
22795    fn range_for_rename(
22796        &self,
22797        buffer: &Entity<Buffer>,
22798        position: text::Anchor,
22799        cx: &mut App,
22800    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22801
22802    fn perform_rename(
22803        &self,
22804        buffer: &Entity<Buffer>,
22805        position: text::Anchor,
22806        new_name: String,
22807        cx: &mut App,
22808    ) -> Option<Task<Result<ProjectTransaction>>>;
22809}
22810
22811pub trait CompletionProvider {
22812    fn completions(
22813        &self,
22814        excerpt_id: ExcerptId,
22815        buffer: &Entity<Buffer>,
22816        buffer_position: text::Anchor,
22817        trigger: CompletionContext,
22818        window: &mut Window,
22819        cx: &mut Context<Editor>,
22820    ) -> Task<Result<Vec<CompletionResponse>>>;
22821
22822    fn resolve_completions(
22823        &self,
22824        _buffer: Entity<Buffer>,
22825        _completion_indices: Vec<usize>,
22826        _completions: Rc<RefCell<Box<[Completion]>>>,
22827        _cx: &mut Context<Editor>,
22828    ) -> Task<Result<bool>> {
22829        Task::ready(Ok(false))
22830    }
22831
22832    fn apply_additional_edits_for_completion(
22833        &self,
22834        _buffer: Entity<Buffer>,
22835        _completions: Rc<RefCell<Box<[Completion]>>>,
22836        _completion_index: usize,
22837        _push_to_history: bool,
22838        _cx: &mut Context<Editor>,
22839    ) -> Task<Result<Option<language::Transaction>>> {
22840        Task::ready(Ok(None))
22841    }
22842
22843    fn is_completion_trigger(
22844        &self,
22845        buffer: &Entity<Buffer>,
22846        position: language::Anchor,
22847        text: &str,
22848        trigger_in_words: bool,
22849        menu_is_open: bool,
22850        cx: &mut Context<Editor>,
22851    ) -> bool;
22852
22853    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22854
22855    fn sort_completions(&self) -> bool {
22856        true
22857    }
22858
22859    fn filter_completions(&self) -> bool {
22860        true
22861    }
22862}
22863
22864pub trait CodeActionProvider {
22865    fn id(&self) -> Arc<str>;
22866
22867    fn code_actions(
22868        &self,
22869        buffer: &Entity<Buffer>,
22870        range: Range<text::Anchor>,
22871        window: &mut Window,
22872        cx: &mut App,
22873    ) -> Task<Result<Vec<CodeAction>>>;
22874
22875    fn apply_code_action(
22876        &self,
22877        buffer_handle: Entity<Buffer>,
22878        action: CodeAction,
22879        excerpt_id: ExcerptId,
22880        push_to_history: bool,
22881        window: &mut Window,
22882        cx: &mut App,
22883    ) -> Task<Result<ProjectTransaction>>;
22884}
22885
22886impl CodeActionProvider for Entity<Project> {
22887    fn id(&self) -> Arc<str> {
22888        "project".into()
22889    }
22890
22891    fn code_actions(
22892        &self,
22893        buffer: &Entity<Buffer>,
22894        range: Range<text::Anchor>,
22895        _window: &mut Window,
22896        cx: &mut App,
22897    ) -> Task<Result<Vec<CodeAction>>> {
22898        self.update(cx, |project, cx| {
22899            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22900            let code_actions = project.code_actions(buffer, range, None, cx);
22901            cx.background_spawn(async move {
22902                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22903                Ok(code_lens_actions
22904                    .context("code lens fetch")?
22905                    .into_iter()
22906                    .flatten()
22907                    .chain(
22908                        code_actions
22909                            .context("code action fetch")?
22910                            .into_iter()
22911                            .flatten(),
22912                    )
22913                    .collect())
22914            })
22915        })
22916    }
22917
22918    fn apply_code_action(
22919        &self,
22920        buffer_handle: Entity<Buffer>,
22921        action: CodeAction,
22922        _excerpt_id: ExcerptId,
22923        push_to_history: bool,
22924        _window: &mut Window,
22925        cx: &mut App,
22926    ) -> Task<Result<ProjectTransaction>> {
22927        self.update(cx, |project, cx| {
22928            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22929        })
22930    }
22931}
22932
22933fn snippet_completions(
22934    project: &Project,
22935    buffer: &Entity<Buffer>,
22936    buffer_position: text::Anchor,
22937    cx: &mut App,
22938) -> Task<Result<CompletionResponse>> {
22939    let languages = buffer.read(cx).languages_at(buffer_position);
22940    let snippet_store = project.snippets().read(cx);
22941
22942    let scopes: Vec<_> = languages
22943        .iter()
22944        .filter_map(|language| {
22945            let language_name = language.lsp_id();
22946            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22947
22948            if snippets.is_empty() {
22949                None
22950            } else {
22951                Some((language.default_scope(), snippets))
22952            }
22953        })
22954        .collect();
22955
22956    if scopes.is_empty() {
22957        return Task::ready(Ok(CompletionResponse {
22958            completions: vec![],
22959            display_options: CompletionDisplayOptions::default(),
22960            is_incomplete: false,
22961        }));
22962    }
22963
22964    let snapshot = buffer.read(cx).text_snapshot();
22965    let executor = cx.background_executor().clone();
22966
22967    cx.background_spawn(async move {
22968        let mut is_incomplete = false;
22969        let mut completions: Vec<Completion> = Vec::new();
22970        for (scope, snippets) in scopes.into_iter() {
22971            let classifier =
22972                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22973
22974            const MAX_WORD_PREFIX_LEN: usize = 128;
22975            let last_word: String = snapshot
22976                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22977                .take(MAX_WORD_PREFIX_LEN)
22978                .take_while(|c| classifier.is_word(*c))
22979                .collect::<String>()
22980                .chars()
22981                .rev()
22982                .collect();
22983
22984            if last_word.is_empty() {
22985                return Ok(CompletionResponse {
22986                    completions: vec![],
22987                    display_options: CompletionDisplayOptions::default(),
22988                    is_incomplete: true,
22989                });
22990            }
22991
22992            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22993            let to_lsp = |point: &text::Anchor| {
22994                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22995                point_to_lsp(end)
22996            };
22997            let lsp_end = to_lsp(&buffer_position);
22998
22999            let candidates = snippets
23000                .iter()
23001                .enumerate()
23002                .flat_map(|(ix, snippet)| {
23003                    snippet
23004                        .prefix
23005                        .iter()
23006                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23007                })
23008                .collect::<Vec<StringMatchCandidate>>();
23009
23010            const MAX_RESULTS: usize = 100;
23011            let mut matches = fuzzy::match_strings(
23012                &candidates,
23013                &last_word,
23014                last_word.chars().any(|c| c.is_uppercase()),
23015                true,
23016                MAX_RESULTS,
23017                &Default::default(),
23018                executor.clone(),
23019            )
23020            .await;
23021
23022            if matches.len() >= MAX_RESULTS {
23023                is_incomplete = true;
23024            }
23025
23026            // Remove all candidates where the query's start does not match the start of any word in the candidate
23027            if let Some(query_start) = last_word.chars().next() {
23028                matches.retain(|string_match| {
23029                    split_words(&string_match.string).any(|word| {
23030                        // Check that the first codepoint of the word as lowercase matches the first
23031                        // codepoint of the query as lowercase
23032                        word.chars()
23033                            .flat_map(|codepoint| codepoint.to_lowercase())
23034                            .zip(query_start.to_lowercase())
23035                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23036                    })
23037                });
23038            }
23039
23040            let matched_strings = matches
23041                .into_iter()
23042                .map(|m| m.string)
23043                .collect::<HashSet<_>>();
23044
23045            completions.extend(snippets.iter().filter_map(|snippet| {
23046                let matching_prefix = snippet
23047                    .prefix
23048                    .iter()
23049                    .find(|prefix| matched_strings.contains(*prefix))?;
23050                let start = as_offset - last_word.len();
23051                let start = snapshot.anchor_before(start);
23052                let range = start..buffer_position;
23053                let lsp_start = to_lsp(&start);
23054                let lsp_range = lsp::Range {
23055                    start: lsp_start,
23056                    end: lsp_end,
23057                };
23058                Some(Completion {
23059                    replace_range: range,
23060                    new_text: snippet.body.clone(),
23061                    source: CompletionSource::Lsp {
23062                        insert_range: None,
23063                        server_id: LanguageServerId(usize::MAX),
23064                        resolved: true,
23065                        lsp_completion: Box::new(lsp::CompletionItem {
23066                            label: snippet.prefix.first().unwrap().clone(),
23067                            kind: Some(CompletionItemKind::SNIPPET),
23068                            label_details: snippet.description.as_ref().map(|description| {
23069                                lsp::CompletionItemLabelDetails {
23070                                    detail: Some(description.clone()),
23071                                    description: None,
23072                                }
23073                            }),
23074                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23075                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23076                                lsp::InsertReplaceEdit {
23077                                    new_text: snippet.body.clone(),
23078                                    insert: lsp_range,
23079                                    replace: lsp_range,
23080                                },
23081                            )),
23082                            filter_text: Some(snippet.body.clone()),
23083                            sort_text: Some(char::MAX.to_string()),
23084                            ..lsp::CompletionItem::default()
23085                        }),
23086                        lsp_defaults: None,
23087                    },
23088                    label: CodeLabel::plain(matching_prefix.clone(), None),
23089                    icon_path: None,
23090                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23091                        single_line: snippet.name.clone().into(),
23092                        plain_text: snippet
23093                            .description
23094                            .clone()
23095                            .map(|description| description.into()),
23096                    }),
23097                    insert_text_mode: None,
23098                    confirm: None,
23099                })
23100            }))
23101        }
23102
23103        Ok(CompletionResponse {
23104            completions,
23105            display_options: CompletionDisplayOptions::default(),
23106            is_incomplete,
23107        })
23108    })
23109}
23110
23111impl CompletionProvider for Entity<Project> {
23112    fn completions(
23113        &self,
23114        _excerpt_id: ExcerptId,
23115        buffer: &Entity<Buffer>,
23116        buffer_position: text::Anchor,
23117        options: CompletionContext,
23118        _window: &mut Window,
23119        cx: &mut Context<Editor>,
23120    ) -> Task<Result<Vec<CompletionResponse>>> {
23121        self.update(cx, |project, cx| {
23122            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23123            let project_completions = project.completions(buffer, buffer_position, options, cx);
23124            cx.background_spawn(async move {
23125                let mut responses = project_completions.await?;
23126                let snippets = snippets.await?;
23127                if !snippets.completions.is_empty() {
23128                    responses.push(snippets);
23129                }
23130                Ok(responses)
23131            })
23132        })
23133    }
23134
23135    fn resolve_completions(
23136        &self,
23137        buffer: Entity<Buffer>,
23138        completion_indices: Vec<usize>,
23139        completions: Rc<RefCell<Box<[Completion]>>>,
23140        cx: &mut Context<Editor>,
23141    ) -> Task<Result<bool>> {
23142        self.update(cx, |project, cx| {
23143            project.lsp_store().update(cx, |lsp_store, cx| {
23144                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23145            })
23146        })
23147    }
23148
23149    fn apply_additional_edits_for_completion(
23150        &self,
23151        buffer: Entity<Buffer>,
23152        completions: Rc<RefCell<Box<[Completion]>>>,
23153        completion_index: usize,
23154        push_to_history: bool,
23155        cx: &mut Context<Editor>,
23156    ) -> Task<Result<Option<language::Transaction>>> {
23157        self.update(cx, |project, cx| {
23158            project.lsp_store().update(cx, |lsp_store, cx| {
23159                lsp_store.apply_additional_edits_for_completion(
23160                    buffer,
23161                    completions,
23162                    completion_index,
23163                    push_to_history,
23164                    cx,
23165                )
23166            })
23167        })
23168    }
23169
23170    fn is_completion_trigger(
23171        &self,
23172        buffer: &Entity<Buffer>,
23173        position: language::Anchor,
23174        text: &str,
23175        trigger_in_words: bool,
23176        menu_is_open: bool,
23177        cx: &mut Context<Editor>,
23178    ) -> bool {
23179        let mut chars = text.chars();
23180        let char = if let Some(char) = chars.next() {
23181            char
23182        } else {
23183            return false;
23184        };
23185        if chars.next().is_some() {
23186            return false;
23187        }
23188
23189        let buffer = buffer.read(cx);
23190        let snapshot = buffer.snapshot();
23191        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23192            return false;
23193        }
23194        let classifier = snapshot
23195            .char_classifier_at(position)
23196            .scope_context(Some(CharScopeContext::Completion));
23197        if trigger_in_words && classifier.is_word(char) {
23198            return true;
23199        }
23200
23201        buffer.completion_triggers().contains(text)
23202    }
23203}
23204
23205impl SemanticsProvider for Entity<Project> {
23206    fn hover(
23207        &self,
23208        buffer: &Entity<Buffer>,
23209        position: text::Anchor,
23210        cx: &mut App,
23211    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23212        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23213    }
23214
23215    fn document_highlights(
23216        &self,
23217        buffer: &Entity<Buffer>,
23218        position: text::Anchor,
23219        cx: &mut App,
23220    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23221        Some(self.update(cx, |project, cx| {
23222            project.document_highlights(buffer, position, cx)
23223        }))
23224    }
23225
23226    fn definitions(
23227        &self,
23228        buffer: &Entity<Buffer>,
23229        position: text::Anchor,
23230        kind: GotoDefinitionKind,
23231        cx: &mut App,
23232    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23233        Some(self.update(cx, |project, cx| match kind {
23234            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23235            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23236            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23237            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23238        }))
23239    }
23240
23241    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23242        self.update(cx, |project, cx| {
23243            if project
23244                .active_debug_session(cx)
23245                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23246            {
23247                return true;
23248            }
23249
23250            buffer.update(cx, |buffer, cx| {
23251                project.any_language_server_supports_inlay_hints(buffer, cx)
23252            })
23253        })
23254    }
23255
23256    fn inline_values(
23257        &self,
23258        buffer_handle: Entity<Buffer>,
23259        range: Range<text::Anchor>,
23260        cx: &mut App,
23261    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23262        self.update(cx, |project, cx| {
23263            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23264
23265            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23266        })
23267    }
23268
23269    fn inlay_hints(
23270        &self,
23271        buffer_handle: Entity<Buffer>,
23272        range: Range<text::Anchor>,
23273        cx: &mut App,
23274    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23275        Some(self.update(cx, |project, cx| {
23276            project.inlay_hints(buffer_handle, range, cx)
23277        }))
23278    }
23279
23280    fn resolve_inlay_hint(
23281        &self,
23282        hint: InlayHint,
23283        buffer_handle: Entity<Buffer>,
23284        server_id: LanguageServerId,
23285        cx: &mut App,
23286    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23287        Some(self.update(cx, |project, cx| {
23288            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23289        }))
23290    }
23291
23292    fn range_for_rename(
23293        &self,
23294        buffer: &Entity<Buffer>,
23295        position: text::Anchor,
23296        cx: &mut App,
23297    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23298        Some(self.update(cx, |project, cx| {
23299            let buffer = buffer.clone();
23300            let task = project.prepare_rename(buffer.clone(), position, cx);
23301            cx.spawn(async move |_, cx| {
23302                Ok(match task.await? {
23303                    PrepareRenameResponse::Success(range) => Some(range),
23304                    PrepareRenameResponse::InvalidPosition => None,
23305                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23306                        // Fallback on using TreeSitter info to determine identifier range
23307                        buffer.read_with(cx, |buffer, _| {
23308                            let snapshot = buffer.snapshot();
23309                            let (range, kind) = snapshot.surrounding_word(position, None);
23310                            if kind != Some(CharKind::Word) {
23311                                return None;
23312                            }
23313                            Some(
23314                                snapshot.anchor_before(range.start)
23315                                    ..snapshot.anchor_after(range.end),
23316                            )
23317                        })?
23318                    }
23319                })
23320            })
23321        }))
23322    }
23323
23324    fn perform_rename(
23325        &self,
23326        buffer: &Entity<Buffer>,
23327        position: text::Anchor,
23328        new_name: String,
23329        cx: &mut App,
23330    ) -> Option<Task<Result<ProjectTransaction>>> {
23331        Some(self.update(cx, |project, cx| {
23332            project.perform_rename(buffer.clone(), position, new_name, cx)
23333        }))
23334    }
23335}
23336
23337fn inlay_hint_settings(
23338    location: Anchor,
23339    snapshot: &MultiBufferSnapshot,
23340    cx: &mut Context<Editor>,
23341) -> InlayHintSettings {
23342    let file = snapshot.file_at(location);
23343    let language = snapshot.language_at(location).map(|l| l.name());
23344    language_settings(language, file, cx).inlay_hints
23345}
23346
23347fn consume_contiguous_rows(
23348    contiguous_row_selections: &mut Vec<Selection<Point>>,
23349    selection: &Selection<Point>,
23350    display_map: &DisplaySnapshot,
23351    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23352) -> (MultiBufferRow, MultiBufferRow) {
23353    contiguous_row_selections.push(selection.clone());
23354    let start_row = starting_row(selection, display_map);
23355    let mut end_row = ending_row(selection, display_map);
23356
23357    while let Some(next_selection) = selections.peek() {
23358        if next_selection.start.row <= end_row.0 {
23359            end_row = ending_row(next_selection, display_map);
23360            contiguous_row_selections.push(selections.next().unwrap().clone());
23361        } else {
23362            break;
23363        }
23364    }
23365    (start_row, end_row)
23366}
23367
23368fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23369    if selection.start.column > 0 {
23370        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23371    } else {
23372        MultiBufferRow(selection.start.row)
23373    }
23374}
23375
23376fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23377    if next_selection.end.column > 0 || next_selection.is_empty() {
23378        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23379    } else {
23380        MultiBufferRow(next_selection.end.row)
23381    }
23382}
23383
23384impl EditorSnapshot {
23385    pub fn remote_selections_in_range<'a>(
23386        &'a self,
23387        range: &'a Range<Anchor>,
23388        collaboration_hub: &dyn CollaborationHub,
23389        cx: &'a App,
23390    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23391        let participant_names = collaboration_hub.user_names(cx);
23392        let participant_indices = collaboration_hub.user_participant_indices(cx);
23393        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23394        let collaborators_by_replica_id = collaborators_by_peer_id
23395            .values()
23396            .map(|collaborator| (collaborator.replica_id, collaborator))
23397            .collect::<HashMap<_, _>>();
23398        self.buffer_snapshot()
23399            .selections_in_range(range, false)
23400            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23401                if replica_id == AGENT_REPLICA_ID {
23402                    Some(RemoteSelection {
23403                        replica_id,
23404                        selection,
23405                        cursor_shape,
23406                        line_mode,
23407                        collaborator_id: CollaboratorId::Agent,
23408                        user_name: Some("Agent".into()),
23409                        color: cx.theme().players().agent(),
23410                    })
23411                } else {
23412                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23413                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23414                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23415                    Some(RemoteSelection {
23416                        replica_id,
23417                        selection,
23418                        cursor_shape,
23419                        line_mode,
23420                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23421                        user_name,
23422                        color: if let Some(index) = participant_index {
23423                            cx.theme().players().color_for_participant(index.0)
23424                        } else {
23425                            cx.theme().players().absent()
23426                        },
23427                    })
23428                }
23429            })
23430    }
23431
23432    pub fn hunks_for_ranges(
23433        &self,
23434        ranges: impl IntoIterator<Item = Range<Point>>,
23435    ) -> Vec<MultiBufferDiffHunk> {
23436        let mut hunks = Vec::new();
23437        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23438            HashMap::default();
23439        for query_range in ranges {
23440            let query_rows =
23441                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23442            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23443                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23444            ) {
23445                // Include deleted hunks that are adjacent to the query range, because
23446                // otherwise they would be missed.
23447                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23448                if hunk.status().is_deleted() {
23449                    intersects_range |= hunk.row_range.start == query_rows.end;
23450                    intersects_range |= hunk.row_range.end == query_rows.start;
23451                }
23452                if intersects_range {
23453                    if !processed_buffer_rows
23454                        .entry(hunk.buffer_id)
23455                        .or_default()
23456                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23457                    {
23458                        continue;
23459                    }
23460                    hunks.push(hunk);
23461                }
23462            }
23463        }
23464
23465        hunks
23466    }
23467
23468    fn display_diff_hunks_for_rows<'a>(
23469        &'a self,
23470        display_rows: Range<DisplayRow>,
23471        folded_buffers: &'a HashSet<BufferId>,
23472    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23473        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23474        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23475
23476        self.buffer_snapshot()
23477            .diff_hunks_in_range(buffer_start..buffer_end)
23478            .filter_map(|hunk| {
23479                if folded_buffers.contains(&hunk.buffer_id) {
23480                    return None;
23481                }
23482
23483                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23484                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23485
23486                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23487                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23488
23489                let display_hunk = if hunk_display_start.column() != 0 {
23490                    DisplayDiffHunk::Folded {
23491                        display_row: hunk_display_start.row(),
23492                    }
23493                } else {
23494                    let mut end_row = hunk_display_end.row();
23495                    if hunk_display_end.column() > 0 {
23496                        end_row.0 += 1;
23497                    }
23498                    let is_created_file = hunk.is_created_file();
23499                    DisplayDiffHunk::Unfolded {
23500                        status: hunk.status(),
23501                        diff_base_byte_range: hunk.diff_base_byte_range,
23502                        display_row_range: hunk_display_start.row()..end_row,
23503                        multi_buffer_range: Anchor::range_in_buffer(
23504                            hunk.excerpt_id,
23505                            hunk.buffer_id,
23506                            hunk.buffer_range,
23507                        ),
23508                        is_created_file,
23509                    }
23510                };
23511
23512                Some(display_hunk)
23513            })
23514    }
23515
23516    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23517        self.display_snapshot
23518            .buffer_snapshot()
23519            .language_at(position)
23520    }
23521
23522    pub fn is_focused(&self) -> bool {
23523        self.is_focused
23524    }
23525
23526    pub fn placeholder_text(&self) -> Option<String> {
23527        self.placeholder_display_snapshot
23528            .as_ref()
23529            .map(|display_map| display_map.text())
23530    }
23531
23532    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23533        self.scroll_anchor.scroll_position(&self.display_snapshot)
23534    }
23535
23536    fn gutter_dimensions(
23537        &self,
23538        font_id: FontId,
23539        font_size: Pixels,
23540        max_line_number_width: Pixels,
23541        cx: &App,
23542    ) -> Option<GutterDimensions> {
23543        if !self.show_gutter {
23544            return None;
23545        }
23546
23547        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23548        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23549
23550        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23551            matches!(
23552                ProjectSettings::get_global(cx).git.git_gutter,
23553                GitGutterSetting::TrackedFiles
23554            )
23555        });
23556        let gutter_settings = EditorSettings::get_global(cx).gutter;
23557        let show_line_numbers = self
23558            .show_line_numbers
23559            .unwrap_or(gutter_settings.line_numbers);
23560        let line_gutter_width = if show_line_numbers {
23561            // Avoid flicker-like gutter resizes when the line number gains another digit by
23562            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23563            let min_width_for_number_on_gutter =
23564                ch_advance * gutter_settings.min_line_number_digits as f32;
23565            max_line_number_width.max(min_width_for_number_on_gutter)
23566        } else {
23567            0.0.into()
23568        };
23569
23570        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23571        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23572
23573        let git_blame_entries_width =
23574            self.git_blame_gutter_max_author_length
23575                .map(|max_author_length| {
23576                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23577                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23578
23579                    /// The number of characters to dedicate to gaps and margins.
23580                    const SPACING_WIDTH: usize = 4;
23581
23582                    let max_char_count = max_author_length.min(renderer.max_author_length())
23583                        + ::git::SHORT_SHA_LENGTH
23584                        + MAX_RELATIVE_TIMESTAMP.len()
23585                        + SPACING_WIDTH;
23586
23587                    ch_advance * max_char_count
23588                });
23589
23590        let is_singleton = self.buffer_snapshot().is_singleton();
23591
23592        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23593        left_padding += if !is_singleton {
23594            ch_width * 4.0
23595        } else if show_runnables || show_breakpoints {
23596            ch_width * 3.0
23597        } else if show_git_gutter && show_line_numbers {
23598            ch_width * 2.0
23599        } else if show_git_gutter || show_line_numbers {
23600            ch_width
23601        } else {
23602            px(0.)
23603        };
23604
23605        let shows_folds = is_singleton && gutter_settings.folds;
23606
23607        let right_padding = if shows_folds && show_line_numbers {
23608            ch_width * 4.0
23609        } else if shows_folds || (!is_singleton && show_line_numbers) {
23610            ch_width * 3.0
23611        } else if show_line_numbers {
23612            ch_width
23613        } else {
23614            px(0.)
23615        };
23616
23617        Some(GutterDimensions {
23618            left_padding,
23619            right_padding,
23620            width: line_gutter_width + left_padding + right_padding,
23621            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23622            git_blame_entries_width,
23623        })
23624    }
23625
23626    pub fn render_crease_toggle(
23627        &self,
23628        buffer_row: MultiBufferRow,
23629        row_contains_cursor: bool,
23630        editor: Entity<Editor>,
23631        window: &mut Window,
23632        cx: &mut App,
23633    ) -> Option<AnyElement> {
23634        let folded = self.is_line_folded(buffer_row);
23635        let mut is_foldable = false;
23636
23637        if let Some(crease) = self
23638            .crease_snapshot
23639            .query_row(buffer_row, self.buffer_snapshot())
23640        {
23641            is_foldable = true;
23642            match crease {
23643                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23644                    if let Some(render_toggle) = render_toggle {
23645                        let toggle_callback =
23646                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23647                                if folded {
23648                                    editor.update(cx, |editor, cx| {
23649                                        editor.fold_at(buffer_row, window, cx)
23650                                    });
23651                                } else {
23652                                    editor.update(cx, |editor, cx| {
23653                                        editor.unfold_at(buffer_row, window, cx)
23654                                    });
23655                                }
23656                            });
23657                        return Some((render_toggle)(
23658                            buffer_row,
23659                            folded,
23660                            toggle_callback,
23661                            window,
23662                            cx,
23663                        ));
23664                    }
23665                }
23666            }
23667        }
23668
23669        is_foldable |= self.starts_indent(buffer_row);
23670
23671        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23672            Some(
23673                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23674                    .toggle_state(folded)
23675                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23676                        if folded {
23677                            this.unfold_at(buffer_row, window, cx);
23678                        } else {
23679                            this.fold_at(buffer_row, window, cx);
23680                        }
23681                    }))
23682                    .into_any_element(),
23683            )
23684        } else {
23685            None
23686        }
23687    }
23688
23689    pub fn render_crease_trailer(
23690        &self,
23691        buffer_row: MultiBufferRow,
23692        window: &mut Window,
23693        cx: &mut App,
23694    ) -> Option<AnyElement> {
23695        let folded = self.is_line_folded(buffer_row);
23696        if let Crease::Inline { render_trailer, .. } = self
23697            .crease_snapshot
23698            .query_row(buffer_row, self.buffer_snapshot())?
23699        {
23700            let render_trailer = render_trailer.as_ref()?;
23701            Some(render_trailer(buffer_row, folded, window, cx))
23702        } else {
23703            None
23704        }
23705    }
23706}
23707
23708impl Deref for EditorSnapshot {
23709    type Target = DisplaySnapshot;
23710
23711    fn deref(&self) -> &Self::Target {
23712        &self.display_snapshot
23713    }
23714}
23715
23716#[derive(Clone, Debug, PartialEq, Eq)]
23717pub enum EditorEvent {
23718    InputIgnored {
23719        text: Arc<str>,
23720    },
23721    InputHandled {
23722        utf16_range_to_replace: Option<Range<isize>>,
23723        text: Arc<str>,
23724    },
23725    ExcerptsAdded {
23726        buffer: Entity<Buffer>,
23727        predecessor: ExcerptId,
23728        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23729    },
23730    ExcerptsRemoved {
23731        ids: Vec<ExcerptId>,
23732        removed_buffer_ids: Vec<BufferId>,
23733    },
23734    BufferFoldToggled {
23735        ids: Vec<ExcerptId>,
23736        folded: bool,
23737    },
23738    ExcerptsEdited {
23739        ids: Vec<ExcerptId>,
23740    },
23741    ExcerptsExpanded {
23742        ids: Vec<ExcerptId>,
23743    },
23744    BufferEdited,
23745    Edited {
23746        transaction_id: clock::Lamport,
23747    },
23748    Reparsed(BufferId),
23749    Focused,
23750    FocusedIn,
23751    Blurred,
23752    DirtyChanged,
23753    Saved,
23754    TitleChanged,
23755    SelectionsChanged {
23756        local: bool,
23757    },
23758    ScrollPositionChanged {
23759        local: bool,
23760        autoscroll: bool,
23761    },
23762    TransactionUndone {
23763        transaction_id: clock::Lamport,
23764    },
23765    TransactionBegun {
23766        transaction_id: clock::Lamport,
23767    },
23768    CursorShapeChanged,
23769    BreadcrumbsChanged,
23770    PushedToNavHistory {
23771        anchor: Anchor,
23772        is_deactivate: bool,
23773    },
23774}
23775
23776impl EventEmitter<EditorEvent> for Editor {}
23777
23778impl Focusable for Editor {
23779    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23780        self.focus_handle.clone()
23781    }
23782}
23783
23784impl Render for Editor {
23785    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23786        let settings = ThemeSettings::get_global(cx);
23787
23788        let mut text_style = match self.mode {
23789            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23790                color: cx.theme().colors().editor_foreground,
23791                font_family: settings.ui_font.family.clone(),
23792                font_features: settings.ui_font.features.clone(),
23793                font_fallbacks: settings.ui_font.fallbacks.clone(),
23794                font_size: rems(0.875).into(),
23795                font_weight: settings.ui_font.weight,
23796                line_height: relative(settings.buffer_line_height.value()),
23797                ..Default::default()
23798            },
23799            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23800                color: cx.theme().colors().editor_foreground,
23801                font_family: settings.buffer_font.family.clone(),
23802                font_features: settings.buffer_font.features.clone(),
23803                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23804                font_size: settings.buffer_font_size(cx).into(),
23805                font_weight: settings.buffer_font.weight,
23806                line_height: relative(settings.buffer_line_height.value()),
23807                ..Default::default()
23808            },
23809        };
23810        if let Some(text_style_refinement) = &self.text_style_refinement {
23811            text_style.refine(text_style_refinement)
23812        }
23813
23814        let background = match self.mode {
23815            EditorMode::SingleLine => cx.theme().system().transparent,
23816            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23817            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23818            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23819        };
23820
23821        EditorElement::new(
23822            &cx.entity(),
23823            EditorStyle {
23824                background,
23825                border: cx.theme().colors().border,
23826                local_player: cx.theme().players().local(),
23827                text: text_style,
23828                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23829                syntax: cx.theme().syntax().clone(),
23830                status: cx.theme().status().clone(),
23831                inlay_hints_style: make_inlay_hints_style(cx),
23832                edit_prediction_styles: make_suggestion_styles(cx),
23833                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23834                show_underlines: self.diagnostics_enabled(),
23835            },
23836        )
23837    }
23838}
23839
23840impl EntityInputHandler for Editor {
23841    fn text_for_range(
23842        &mut self,
23843        range_utf16: Range<usize>,
23844        adjusted_range: &mut Option<Range<usize>>,
23845        _: &mut Window,
23846        cx: &mut Context<Self>,
23847    ) -> Option<String> {
23848        let snapshot = self.buffer.read(cx).read(cx);
23849        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23850        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23851        if (start.0..end.0) != range_utf16 {
23852            adjusted_range.replace(start.0..end.0);
23853        }
23854        Some(snapshot.text_for_range(start..end).collect())
23855    }
23856
23857    fn selected_text_range(
23858        &mut self,
23859        ignore_disabled_input: bool,
23860        _: &mut Window,
23861        cx: &mut Context<Self>,
23862    ) -> Option<UTF16Selection> {
23863        // Prevent the IME menu from appearing when holding down an alphabetic key
23864        // while input is disabled.
23865        if !ignore_disabled_input && !self.input_enabled {
23866            return None;
23867        }
23868
23869        let selection = self.selections.newest::<OffsetUtf16>(cx);
23870        let range = selection.range();
23871
23872        Some(UTF16Selection {
23873            range: range.start.0..range.end.0,
23874            reversed: selection.reversed,
23875        })
23876    }
23877
23878    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23879        let snapshot = self.buffer.read(cx).read(cx);
23880        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23881        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23882    }
23883
23884    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23885        self.clear_highlights::<InputComposition>(cx);
23886        self.ime_transaction.take();
23887    }
23888
23889    fn replace_text_in_range(
23890        &mut self,
23891        range_utf16: Option<Range<usize>>,
23892        text: &str,
23893        window: &mut Window,
23894        cx: &mut Context<Self>,
23895    ) {
23896        if !self.input_enabled {
23897            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23898            return;
23899        }
23900
23901        self.transact(window, cx, |this, window, cx| {
23902            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23903                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23904                Some(this.selection_replacement_ranges(range_utf16, cx))
23905            } else {
23906                this.marked_text_ranges(cx)
23907            };
23908
23909            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23910                let newest_selection_id = this.selections.newest_anchor().id;
23911                this.selections
23912                    .all::<OffsetUtf16>(cx)
23913                    .iter()
23914                    .zip(ranges_to_replace.iter())
23915                    .find_map(|(selection, range)| {
23916                        if selection.id == newest_selection_id {
23917                            Some(
23918                                (range.start.0 as isize - selection.head().0 as isize)
23919                                    ..(range.end.0 as isize - selection.head().0 as isize),
23920                            )
23921                        } else {
23922                            None
23923                        }
23924                    })
23925            });
23926
23927            cx.emit(EditorEvent::InputHandled {
23928                utf16_range_to_replace: range_to_replace,
23929                text: text.into(),
23930            });
23931
23932            if let Some(new_selected_ranges) = new_selected_ranges {
23933                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23934                    selections.select_ranges(new_selected_ranges)
23935                });
23936                this.backspace(&Default::default(), window, cx);
23937            }
23938
23939            this.handle_input(text, window, cx);
23940        });
23941
23942        if let Some(transaction) = self.ime_transaction {
23943            self.buffer.update(cx, |buffer, cx| {
23944                buffer.group_until_transaction(transaction, cx);
23945            });
23946        }
23947
23948        self.unmark_text(window, cx);
23949    }
23950
23951    fn replace_and_mark_text_in_range(
23952        &mut self,
23953        range_utf16: Option<Range<usize>>,
23954        text: &str,
23955        new_selected_range_utf16: Option<Range<usize>>,
23956        window: &mut Window,
23957        cx: &mut Context<Self>,
23958    ) {
23959        if !self.input_enabled {
23960            return;
23961        }
23962
23963        let transaction = self.transact(window, cx, |this, window, cx| {
23964            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23965                let snapshot = this.buffer.read(cx).read(cx);
23966                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23967                    for marked_range in &mut marked_ranges {
23968                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23969                        marked_range.start.0 += relative_range_utf16.start;
23970                        marked_range.start =
23971                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23972                        marked_range.end =
23973                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23974                    }
23975                }
23976                Some(marked_ranges)
23977            } else if let Some(range_utf16) = range_utf16 {
23978                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23979                Some(this.selection_replacement_ranges(range_utf16, cx))
23980            } else {
23981                None
23982            };
23983
23984            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23985                let newest_selection_id = this.selections.newest_anchor().id;
23986                this.selections
23987                    .all::<OffsetUtf16>(cx)
23988                    .iter()
23989                    .zip(ranges_to_replace.iter())
23990                    .find_map(|(selection, range)| {
23991                        if selection.id == newest_selection_id {
23992                            Some(
23993                                (range.start.0 as isize - selection.head().0 as isize)
23994                                    ..(range.end.0 as isize - selection.head().0 as isize),
23995                            )
23996                        } else {
23997                            None
23998                        }
23999                    })
24000            });
24001
24002            cx.emit(EditorEvent::InputHandled {
24003                utf16_range_to_replace: range_to_replace,
24004                text: text.into(),
24005            });
24006
24007            if let Some(ranges) = ranges_to_replace {
24008                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24009                    s.select_ranges(ranges)
24010                });
24011            }
24012
24013            let marked_ranges = {
24014                let snapshot = this.buffer.read(cx).read(cx);
24015                this.selections
24016                    .disjoint_anchors_arc()
24017                    .iter()
24018                    .map(|selection| {
24019                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24020                    })
24021                    .collect::<Vec<_>>()
24022            };
24023
24024            if text.is_empty() {
24025                this.unmark_text(window, cx);
24026            } else {
24027                this.highlight_text::<InputComposition>(
24028                    marked_ranges.clone(),
24029                    HighlightStyle {
24030                        underline: Some(UnderlineStyle {
24031                            thickness: px(1.),
24032                            color: None,
24033                            wavy: false,
24034                        }),
24035                        ..Default::default()
24036                    },
24037                    cx,
24038                );
24039            }
24040
24041            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24042            let use_autoclose = this.use_autoclose;
24043            let use_auto_surround = this.use_auto_surround;
24044            this.set_use_autoclose(false);
24045            this.set_use_auto_surround(false);
24046            this.handle_input(text, window, cx);
24047            this.set_use_autoclose(use_autoclose);
24048            this.set_use_auto_surround(use_auto_surround);
24049
24050            if let Some(new_selected_range) = new_selected_range_utf16 {
24051                let snapshot = this.buffer.read(cx).read(cx);
24052                let new_selected_ranges = marked_ranges
24053                    .into_iter()
24054                    .map(|marked_range| {
24055                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24056                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24057                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24058                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24059                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24060                    })
24061                    .collect::<Vec<_>>();
24062
24063                drop(snapshot);
24064                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24065                    selections.select_ranges(new_selected_ranges)
24066                });
24067            }
24068        });
24069
24070        self.ime_transaction = self.ime_transaction.or(transaction);
24071        if let Some(transaction) = self.ime_transaction {
24072            self.buffer.update(cx, |buffer, cx| {
24073                buffer.group_until_transaction(transaction, cx);
24074            });
24075        }
24076
24077        if self.text_highlights::<InputComposition>(cx).is_none() {
24078            self.ime_transaction.take();
24079        }
24080    }
24081
24082    fn bounds_for_range(
24083        &mut self,
24084        range_utf16: Range<usize>,
24085        element_bounds: gpui::Bounds<Pixels>,
24086        window: &mut Window,
24087        cx: &mut Context<Self>,
24088    ) -> Option<gpui::Bounds<Pixels>> {
24089        let text_layout_details = self.text_layout_details(window);
24090        let CharacterDimensions {
24091            em_width,
24092            em_advance,
24093            line_height,
24094        } = self.character_dimensions(window);
24095
24096        let snapshot = self.snapshot(window, cx);
24097        let scroll_position = snapshot.scroll_position();
24098        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24099
24100        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24101        let x = Pixels::from(
24102            ScrollOffset::from(
24103                snapshot.x_for_display_point(start, &text_layout_details)
24104                    + self.gutter_dimensions.full_width(),
24105            ) - scroll_left,
24106        );
24107        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24108
24109        Some(Bounds {
24110            origin: element_bounds.origin + point(x, y),
24111            size: size(em_width, line_height),
24112        })
24113    }
24114
24115    fn character_index_for_point(
24116        &mut self,
24117        point: gpui::Point<Pixels>,
24118        _window: &mut Window,
24119        _cx: &mut Context<Self>,
24120    ) -> Option<usize> {
24121        let position_map = self.last_position_map.as_ref()?;
24122        if !position_map.text_hitbox.contains(&point) {
24123            return None;
24124        }
24125        let display_point = position_map.point_for_position(point).previous_valid;
24126        let anchor = position_map
24127            .snapshot
24128            .display_point_to_anchor(display_point, Bias::Left);
24129        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24130        Some(utf16_offset.0)
24131    }
24132}
24133
24134trait SelectionExt {
24135    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24136    fn spanned_rows(
24137        &self,
24138        include_end_if_at_line_start: bool,
24139        map: &DisplaySnapshot,
24140    ) -> Range<MultiBufferRow>;
24141}
24142
24143impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24144    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24145        let start = self
24146            .start
24147            .to_point(map.buffer_snapshot())
24148            .to_display_point(map);
24149        let end = self
24150            .end
24151            .to_point(map.buffer_snapshot())
24152            .to_display_point(map);
24153        if self.reversed {
24154            end..start
24155        } else {
24156            start..end
24157        }
24158    }
24159
24160    fn spanned_rows(
24161        &self,
24162        include_end_if_at_line_start: bool,
24163        map: &DisplaySnapshot,
24164    ) -> Range<MultiBufferRow> {
24165        let start = self.start.to_point(map.buffer_snapshot());
24166        let mut end = self.end.to_point(map.buffer_snapshot());
24167        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24168            end.row -= 1;
24169        }
24170
24171        let buffer_start = map.prev_line_boundary(start).0;
24172        let buffer_end = map.next_line_boundary(end).0;
24173        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24174    }
24175}
24176
24177impl<T: InvalidationRegion> InvalidationStack<T> {
24178    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24179    where
24180        S: Clone + ToOffset,
24181    {
24182        while let Some(region) = self.last() {
24183            let all_selections_inside_invalidation_ranges =
24184                if selections.len() == region.ranges().len() {
24185                    selections
24186                        .iter()
24187                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24188                        .all(|(selection, invalidation_range)| {
24189                            let head = selection.head().to_offset(buffer);
24190                            invalidation_range.start <= head && invalidation_range.end >= head
24191                        })
24192                } else {
24193                    false
24194                };
24195
24196            if all_selections_inside_invalidation_ranges {
24197                break;
24198            } else {
24199                self.pop();
24200            }
24201        }
24202    }
24203}
24204
24205impl<T> Default for InvalidationStack<T> {
24206    fn default() -> Self {
24207        Self(Default::default())
24208    }
24209}
24210
24211impl<T> Deref for InvalidationStack<T> {
24212    type Target = Vec<T>;
24213
24214    fn deref(&self) -> &Self::Target {
24215        &self.0
24216    }
24217}
24218
24219impl<T> DerefMut for InvalidationStack<T> {
24220    fn deref_mut(&mut self) -> &mut Self::Target {
24221        &mut self.0
24222    }
24223}
24224
24225impl InvalidationRegion for SnippetState {
24226    fn ranges(&self) -> &[Range<Anchor>] {
24227        &self.ranges[self.active_index]
24228    }
24229}
24230
24231fn edit_prediction_edit_text(
24232    current_snapshot: &BufferSnapshot,
24233    edits: &[(Range<Anchor>, String)],
24234    edit_preview: &EditPreview,
24235    include_deletions: bool,
24236    cx: &App,
24237) -> HighlightedText {
24238    let edits = edits
24239        .iter()
24240        .map(|(anchor, text)| {
24241            (
24242                anchor.start.text_anchor..anchor.end.text_anchor,
24243                text.clone(),
24244            )
24245        })
24246        .collect::<Vec<_>>();
24247
24248    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24249}
24250
24251fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24252    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24253    // Just show the raw edit text with basic styling
24254    let mut text = String::new();
24255    let mut highlights = Vec::new();
24256
24257    let insertion_highlight_style = HighlightStyle {
24258        color: Some(cx.theme().colors().text),
24259        ..Default::default()
24260    };
24261
24262    for (_, edit_text) in edits {
24263        let start_offset = text.len();
24264        text.push_str(edit_text);
24265        let end_offset = text.len();
24266
24267        if start_offset < end_offset {
24268            highlights.push((start_offset..end_offset, insertion_highlight_style));
24269        }
24270    }
24271
24272    HighlightedText {
24273        text: text.into(),
24274        highlights,
24275    }
24276}
24277
24278pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24279    match severity {
24280        lsp::DiagnosticSeverity::ERROR => colors.error,
24281        lsp::DiagnosticSeverity::WARNING => colors.warning,
24282        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24283        lsp::DiagnosticSeverity::HINT => colors.info,
24284        _ => colors.ignored,
24285    }
24286}
24287
24288pub fn styled_runs_for_code_label<'a>(
24289    label: &'a CodeLabel,
24290    syntax_theme: &'a theme::SyntaxTheme,
24291) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24292    let fade_out = HighlightStyle {
24293        fade_out: Some(0.35),
24294        ..Default::default()
24295    };
24296
24297    let mut prev_end = label.filter_range.end;
24298    label
24299        .runs
24300        .iter()
24301        .enumerate()
24302        .flat_map(move |(ix, (range, highlight_id))| {
24303            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24304                style
24305            } else {
24306                return Default::default();
24307            };
24308            let muted_style = style.highlight(fade_out);
24309
24310            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24311            if range.start >= label.filter_range.end {
24312                if range.start > prev_end {
24313                    runs.push((prev_end..range.start, fade_out));
24314                }
24315                runs.push((range.clone(), muted_style));
24316            } else if range.end <= label.filter_range.end {
24317                runs.push((range.clone(), style));
24318            } else {
24319                runs.push((range.start..label.filter_range.end, style));
24320                runs.push((label.filter_range.end..range.end, muted_style));
24321            }
24322            prev_end = cmp::max(prev_end, range.end);
24323
24324            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24325                runs.push((prev_end..label.text.len(), fade_out));
24326            }
24327
24328            runs
24329        })
24330}
24331
24332pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24333    let mut prev_index = 0;
24334    let mut prev_codepoint: Option<char> = None;
24335    text.char_indices()
24336        .chain([(text.len(), '\0')])
24337        .filter_map(move |(index, codepoint)| {
24338            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24339            let is_boundary = index == text.len()
24340                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24341                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24342            if is_boundary {
24343                let chunk = &text[prev_index..index];
24344                prev_index = index;
24345                Some(chunk)
24346            } else {
24347                None
24348            }
24349        })
24350}
24351
24352pub trait RangeToAnchorExt: Sized {
24353    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24354
24355    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24356        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24357        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24358    }
24359}
24360
24361impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24362    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24363        let start_offset = self.start.to_offset(snapshot);
24364        let end_offset = self.end.to_offset(snapshot);
24365        if start_offset == end_offset {
24366            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24367        } else {
24368            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24369        }
24370    }
24371}
24372
24373pub trait RowExt {
24374    fn as_f64(&self) -> f64;
24375
24376    fn next_row(&self) -> Self;
24377
24378    fn previous_row(&self) -> Self;
24379
24380    fn minus(&self, other: Self) -> u32;
24381}
24382
24383impl RowExt for DisplayRow {
24384    fn as_f64(&self) -> f64 {
24385        self.0 as _
24386    }
24387
24388    fn next_row(&self) -> Self {
24389        Self(self.0 + 1)
24390    }
24391
24392    fn previous_row(&self) -> Self {
24393        Self(self.0.saturating_sub(1))
24394    }
24395
24396    fn minus(&self, other: Self) -> u32 {
24397        self.0 - other.0
24398    }
24399}
24400
24401impl RowExt for MultiBufferRow {
24402    fn as_f64(&self) -> f64 {
24403        self.0 as _
24404    }
24405
24406    fn next_row(&self) -> Self {
24407        Self(self.0 + 1)
24408    }
24409
24410    fn previous_row(&self) -> Self {
24411        Self(self.0.saturating_sub(1))
24412    }
24413
24414    fn minus(&self, other: Self) -> u32 {
24415        self.0 - other.0
24416    }
24417}
24418
24419trait RowRangeExt {
24420    type Row;
24421
24422    fn len(&self) -> usize;
24423
24424    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24425}
24426
24427impl RowRangeExt for Range<MultiBufferRow> {
24428    type Row = MultiBufferRow;
24429
24430    fn len(&self) -> usize {
24431        (self.end.0 - self.start.0) as usize
24432    }
24433
24434    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24435        (self.start.0..self.end.0).map(MultiBufferRow)
24436    }
24437}
24438
24439impl RowRangeExt for Range<DisplayRow> {
24440    type Row = DisplayRow;
24441
24442    fn len(&self) -> usize {
24443        (self.end.0 - self.start.0) as usize
24444    }
24445
24446    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24447        (self.start.0..self.end.0).map(DisplayRow)
24448    }
24449}
24450
24451/// If select range has more than one line, we
24452/// just point the cursor to range.start.
24453fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24454    if range.start.row == range.end.row {
24455        range
24456    } else {
24457        range.start..range.start
24458    }
24459}
24460pub struct KillRing(ClipboardItem);
24461impl Global for KillRing {}
24462
24463const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24464
24465enum BreakpointPromptEditAction {
24466    Log,
24467    Condition,
24468    HitCondition,
24469}
24470
24471struct BreakpointPromptEditor {
24472    pub(crate) prompt: Entity<Editor>,
24473    editor: WeakEntity<Editor>,
24474    breakpoint_anchor: Anchor,
24475    breakpoint: Breakpoint,
24476    edit_action: BreakpointPromptEditAction,
24477    block_ids: HashSet<CustomBlockId>,
24478    editor_margins: Arc<Mutex<EditorMargins>>,
24479    _subscriptions: Vec<Subscription>,
24480}
24481
24482impl BreakpointPromptEditor {
24483    const MAX_LINES: u8 = 4;
24484
24485    fn new(
24486        editor: WeakEntity<Editor>,
24487        breakpoint_anchor: Anchor,
24488        breakpoint: Breakpoint,
24489        edit_action: BreakpointPromptEditAction,
24490        window: &mut Window,
24491        cx: &mut Context<Self>,
24492    ) -> Self {
24493        let base_text = match edit_action {
24494            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24495            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24496            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24497        }
24498        .map(|msg| msg.to_string())
24499        .unwrap_or_default();
24500
24501        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24502        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24503
24504        let prompt = cx.new(|cx| {
24505            let mut prompt = Editor::new(
24506                EditorMode::AutoHeight {
24507                    min_lines: 1,
24508                    max_lines: Some(Self::MAX_LINES as usize),
24509                },
24510                buffer,
24511                None,
24512                window,
24513                cx,
24514            );
24515            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24516            prompt.set_show_cursor_when_unfocused(false, cx);
24517            prompt.set_placeholder_text(
24518                match edit_action {
24519                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24520                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24521                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24522                },
24523                window,
24524                cx,
24525            );
24526
24527            prompt
24528        });
24529
24530        Self {
24531            prompt,
24532            editor,
24533            breakpoint_anchor,
24534            breakpoint,
24535            edit_action,
24536            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24537            block_ids: Default::default(),
24538            _subscriptions: vec![],
24539        }
24540    }
24541
24542    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24543        self.block_ids.extend(block_ids)
24544    }
24545
24546    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24547        if let Some(editor) = self.editor.upgrade() {
24548            let message = self
24549                .prompt
24550                .read(cx)
24551                .buffer
24552                .read(cx)
24553                .as_singleton()
24554                .expect("A multi buffer in breakpoint prompt isn't possible")
24555                .read(cx)
24556                .as_rope()
24557                .to_string();
24558
24559            editor.update(cx, |editor, cx| {
24560                editor.edit_breakpoint_at_anchor(
24561                    self.breakpoint_anchor,
24562                    self.breakpoint.clone(),
24563                    match self.edit_action {
24564                        BreakpointPromptEditAction::Log => {
24565                            BreakpointEditAction::EditLogMessage(message.into())
24566                        }
24567                        BreakpointPromptEditAction::Condition => {
24568                            BreakpointEditAction::EditCondition(message.into())
24569                        }
24570                        BreakpointPromptEditAction::HitCondition => {
24571                            BreakpointEditAction::EditHitCondition(message.into())
24572                        }
24573                    },
24574                    cx,
24575                );
24576
24577                editor.remove_blocks(self.block_ids.clone(), None, cx);
24578                cx.focus_self(window);
24579            });
24580        }
24581    }
24582
24583    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24584        self.editor
24585            .update(cx, |editor, cx| {
24586                editor.remove_blocks(self.block_ids.clone(), None, cx);
24587                window.focus(&editor.focus_handle);
24588            })
24589            .log_err();
24590    }
24591
24592    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24593        let settings = ThemeSettings::get_global(cx);
24594        let text_style = TextStyle {
24595            color: if self.prompt.read(cx).read_only(cx) {
24596                cx.theme().colors().text_disabled
24597            } else {
24598                cx.theme().colors().text
24599            },
24600            font_family: settings.buffer_font.family.clone(),
24601            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24602            font_size: settings.buffer_font_size(cx).into(),
24603            font_weight: settings.buffer_font.weight,
24604            line_height: relative(settings.buffer_line_height.value()),
24605            ..Default::default()
24606        };
24607        EditorElement::new(
24608            &self.prompt,
24609            EditorStyle {
24610                background: cx.theme().colors().editor_background,
24611                local_player: cx.theme().players().local(),
24612                text: text_style,
24613                ..Default::default()
24614            },
24615        )
24616    }
24617}
24618
24619impl Render for BreakpointPromptEditor {
24620    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24621        let editor_margins = *self.editor_margins.lock();
24622        let gutter_dimensions = editor_margins.gutter;
24623        h_flex()
24624            .key_context("Editor")
24625            .bg(cx.theme().colors().editor_background)
24626            .border_y_1()
24627            .border_color(cx.theme().status().info_border)
24628            .size_full()
24629            .py(window.line_height() / 2.5)
24630            .on_action(cx.listener(Self::confirm))
24631            .on_action(cx.listener(Self::cancel))
24632            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24633            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24634    }
24635}
24636
24637impl Focusable for BreakpointPromptEditor {
24638    fn focus_handle(&self, cx: &App) -> FocusHandle {
24639        self.prompt.focus_handle(cx)
24640    }
24641}
24642
24643fn all_edits_insertions_or_deletions(
24644    edits: &Vec<(Range<Anchor>, String)>,
24645    snapshot: &MultiBufferSnapshot,
24646) -> bool {
24647    let mut all_insertions = true;
24648    let mut all_deletions = true;
24649
24650    for (range, new_text) in edits.iter() {
24651        let range_is_empty = range.to_offset(snapshot).is_empty();
24652        let text_is_empty = new_text.is_empty();
24653
24654        if range_is_empty != text_is_empty {
24655            if range_is_empty {
24656                all_deletions = false;
24657            } else {
24658                all_insertions = false;
24659            }
24660        } else {
24661            return false;
24662        }
24663
24664        if !all_insertions && !all_deletions {
24665            return false;
24666        }
24667    }
24668    all_insertions || all_deletions
24669}
24670
24671struct MissingEditPredictionKeybindingTooltip;
24672
24673impl Render for MissingEditPredictionKeybindingTooltip {
24674    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24675        ui::tooltip_container(cx, |container, cx| {
24676            container
24677                .flex_shrink_0()
24678                .max_w_80()
24679                .min_h(rems_from_px(124.))
24680                .justify_between()
24681                .child(
24682                    v_flex()
24683                        .flex_1()
24684                        .text_ui_sm(cx)
24685                        .child(Label::new("Conflict with Accept Keybinding"))
24686                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24687                )
24688                .child(
24689                    h_flex()
24690                        .pb_1()
24691                        .gap_1()
24692                        .items_end()
24693                        .w_full()
24694                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24695                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24696                        }))
24697                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24698                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24699                        })),
24700                )
24701        })
24702    }
24703}
24704
24705#[derive(Debug, Clone, Copy, PartialEq)]
24706pub struct LineHighlight {
24707    pub background: Background,
24708    pub border: Option<gpui::Hsla>,
24709    pub include_gutter: bool,
24710    pub type_id: Option<TypeId>,
24711}
24712
24713struct LineManipulationResult {
24714    pub new_text: String,
24715    pub line_count_before: usize,
24716    pub line_count_after: usize,
24717}
24718
24719fn render_diff_hunk_controls(
24720    row: u32,
24721    status: &DiffHunkStatus,
24722    hunk_range: Range<Anchor>,
24723    is_created_file: bool,
24724    line_height: Pixels,
24725    editor: &Entity<Editor>,
24726    _window: &mut Window,
24727    cx: &mut App,
24728) -> AnyElement {
24729    h_flex()
24730        .h(line_height)
24731        .mr_1()
24732        .gap_1()
24733        .px_0p5()
24734        .pb_1()
24735        .border_x_1()
24736        .border_b_1()
24737        .border_color(cx.theme().colors().border_variant)
24738        .rounded_b_lg()
24739        .bg(cx.theme().colors().editor_background)
24740        .gap_1()
24741        .block_mouse_except_scroll()
24742        .shadow_md()
24743        .child(if status.has_secondary_hunk() {
24744            Button::new(("stage", row as u64), "Stage")
24745                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24746                .tooltip({
24747                    let focus_handle = editor.focus_handle(cx);
24748                    move |window, cx| {
24749                        Tooltip::for_action_in(
24750                            "Stage Hunk",
24751                            &::git::ToggleStaged,
24752                            &focus_handle,
24753                            window,
24754                            cx,
24755                        )
24756                    }
24757                })
24758                .on_click({
24759                    let editor = editor.clone();
24760                    move |_event, _window, cx| {
24761                        editor.update(cx, |editor, cx| {
24762                            editor.stage_or_unstage_diff_hunks(
24763                                true,
24764                                vec![hunk_range.start..hunk_range.start],
24765                                cx,
24766                            );
24767                        });
24768                    }
24769                })
24770        } else {
24771            Button::new(("unstage", row as u64), "Unstage")
24772                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24773                .tooltip({
24774                    let focus_handle = editor.focus_handle(cx);
24775                    move |window, cx| {
24776                        Tooltip::for_action_in(
24777                            "Unstage Hunk",
24778                            &::git::ToggleStaged,
24779                            &focus_handle,
24780                            window,
24781                            cx,
24782                        )
24783                    }
24784                })
24785                .on_click({
24786                    let editor = editor.clone();
24787                    move |_event, _window, cx| {
24788                        editor.update(cx, |editor, cx| {
24789                            editor.stage_or_unstage_diff_hunks(
24790                                false,
24791                                vec![hunk_range.start..hunk_range.start],
24792                                cx,
24793                            );
24794                        });
24795                    }
24796                })
24797        })
24798        .child(
24799            Button::new(("restore", row as u64), "Restore")
24800                .tooltip({
24801                    let focus_handle = editor.focus_handle(cx);
24802                    move |window, cx| {
24803                        Tooltip::for_action_in(
24804                            "Restore Hunk",
24805                            &::git::Restore,
24806                            &focus_handle,
24807                            window,
24808                            cx,
24809                        )
24810                    }
24811                })
24812                .on_click({
24813                    let editor = editor.clone();
24814                    move |_event, window, cx| {
24815                        editor.update(cx, |editor, cx| {
24816                            let snapshot = editor.snapshot(window, cx);
24817                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24818                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24819                        });
24820                    }
24821                })
24822                .disabled(is_created_file),
24823        )
24824        .when(
24825            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24826            |el| {
24827                el.child(
24828                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24829                        .shape(IconButtonShape::Square)
24830                        .icon_size(IconSize::Small)
24831                        // .disabled(!has_multiple_hunks)
24832                        .tooltip({
24833                            let focus_handle = editor.focus_handle(cx);
24834                            move |window, cx| {
24835                                Tooltip::for_action_in(
24836                                    "Next Hunk",
24837                                    &GoToHunk,
24838                                    &focus_handle,
24839                                    window,
24840                                    cx,
24841                                )
24842                            }
24843                        })
24844                        .on_click({
24845                            let editor = editor.clone();
24846                            move |_event, window, cx| {
24847                                editor.update(cx, |editor, cx| {
24848                                    let snapshot = editor.snapshot(window, cx);
24849                                    let position =
24850                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24851                                    editor.go_to_hunk_before_or_after_position(
24852                                        &snapshot,
24853                                        position,
24854                                        Direction::Next,
24855                                        window,
24856                                        cx,
24857                                    );
24858                                    editor.expand_selected_diff_hunks(cx);
24859                                });
24860                            }
24861                        }),
24862                )
24863                .child(
24864                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24865                        .shape(IconButtonShape::Square)
24866                        .icon_size(IconSize::Small)
24867                        // .disabled(!has_multiple_hunks)
24868                        .tooltip({
24869                            let focus_handle = editor.focus_handle(cx);
24870                            move |window, cx| {
24871                                Tooltip::for_action_in(
24872                                    "Previous Hunk",
24873                                    &GoToPreviousHunk,
24874                                    &focus_handle,
24875                                    window,
24876                                    cx,
24877                                )
24878                            }
24879                        })
24880                        .on_click({
24881                            let editor = editor.clone();
24882                            move |_event, window, cx| {
24883                                editor.update(cx, |editor, cx| {
24884                                    let snapshot = editor.snapshot(window, cx);
24885                                    let point =
24886                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24887                                    editor.go_to_hunk_before_or_after_position(
24888                                        &snapshot,
24889                                        point,
24890                                        Direction::Prev,
24891                                        window,
24892                                        cx,
24893                                    );
24894                                    editor.expand_selected_diff_hunks(cx);
24895                                });
24896                            }
24897                        }),
24898                )
24899            },
24900        )
24901        .into_any_element()
24902}
24903
24904pub fn multibuffer_context_lines(cx: &App) -> u32 {
24905    EditorSettings::try_get(cx)
24906        .map(|settings| settings.excerpt_context_lines)
24907        .unwrap_or(2)
24908        .min(32)
24909}