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::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_split);
  362            workspace.register_action(Editor::new_file_vertical);
  363            workspace.register_action(Editor::new_file_horizontal);
  364            workspace.register_action(Editor::cancel_language_server_work);
  365            workspace.register_action(Editor::toggle_focus);
  366        },
  367    )
  368    .detach();
  369
  370    cx.on_action(move |_: &workspace::NewFile, cx| {
  371        let app_state = workspace::AppState::global(cx);
  372        if let Some(app_state) = app_state.upgrade() {
  373            workspace::open_new(
  374                Default::default(),
  375                app_state,
  376                cx,
  377                |workspace, window, cx| {
  378                    Editor::new_file(workspace, &Default::default(), window, cx)
  379                },
  380            )
  381            .detach();
  382        }
  383    });
  384    cx.on_action(move |_: &workspace::NewWindow, cx| {
  385        let app_state = workspace::AppState::global(cx);
  386        if let Some(app_state) = app_state.upgrade() {
  387            workspace::open_new(
  388                Default::default(),
  389                app_state,
  390                cx,
  391                |workspace, window, cx| {
  392                    cx.activate(true);
  393                    Editor::new_file(workspace, &Default::default(), window, cx)
  394                },
  395            )
  396            .detach();
  397        }
  398    });
  399}
  400
  401pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  402    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  403}
  404
  405pub trait DiagnosticRenderer {
  406    fn render_group(
  407        &self,
  408        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  409        buffer_id: BufferId,
  410        snapshot: EditorSnapshot,
  411        editor: WeakEntity<Editor>,
  412        cx: &mut App,
  413    ) -> Vec<BlockProperties<Anchor>>;
  414
  415    fn render_hover(
  416        &self,
  417        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  418        range: Range<Point>,
  419        buffer_id: BufferId,
  420        cx: &mut App,
  421    ) -> Option<Entity<markdown::Markdown>>;
  422
  423    fn open_link(
  424        &self,
  425        editor: &mut Editor,
  426        link: SharedString,
  427        window: &mut Window,
  428        cx: &mut Context<Editor>,
  429    );
  430}
  431
  432pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  433
  434impl GlobalDiagnosticRenderer {
  435    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  436        cx.try_global::<Self>().map(|g| g.0.clone())
  437    }
  438}
  439
  440impl gpui::Global for GlobalDiagnosticRenderer {}
  441pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  442    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  443}
  444
  445pub struct SearchWithinRange;
  446
  447trait InvalidationRegion {
  448    fn ranges(&self) -> &[Range<Anchor>];
  449}
  450
  451#[derive(Clone, Debug, PartialEq)]
  452pub enum SelectPhase {
  453    Begin {
  454        position: DisplayPoint,
  455        add: bool,
  456        click_count: usize,
  457    },
  458    BeginColumnar {
  459        position: DisplayPoint,
  460        reset: bool,
  461        mode: ColumnarMode,
  462        goal_column: u32,
  463    },
  464    Extend {
  465        position: DisplayPoint,
  466        click_count: usize,
  467    },
  468    Update {
  469        position: DisplayPoint,
  470        goal_column: u32,
  471        scroll_delta: gpui::Point<f32>,
  472    },
  473    End,
  474}
  475
  476#[derive(Clone, Debug, PartialEq)]
  477pub enum ColumnarMode {
  478    FromMouse,
  479    FromSelection,
  480}
  481
  482#[derive(Clone, Debug)]
  483pub enum SelectMode {
  484    Character,
  485    Word(Range<Anchor>),
  486    Line(Range<Anchor>),
  487    All,
  488}
  489
  490#[derive(Clone, PartialEq, Eq, Debug)]
  491pub enum EditorMode {
  492    SingleLine,
  493    AutoHeight {
  494        min_lines: usize,
  495        max_lines: Option<usize>,
  496    },
  497    Full {
  498        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  499        scale_ui_elements_with_buffer_font_size: bool,
  500        /// When set to `true`, the editor will render a background for the active line.
  501        show_active_line_background: bool,
  502        /// When set to `true`, the editor's height will be determined by its content.
  503        sized_by_content: bool,
  504    },
  505    Minimap {
  506        parent: WeakEntity<Editor>,
  507    },
  508}
  509
  510impl EditorMode {
  511    pub fn full() -> Self {
  512        Self::Full {
  513            scale_ui_elements_with_buffer_font_size: true,
  514            show_active_line_background: true,
  515            sized_by_content: false,
  516        }
  517    }
  518
  519    #[inline]
  520    pub fn is_full(&self) -> bool {
  521        matches!(self, Self::Full { .. })
  522    }
  523
  524    #[inline]
  525    pub fn is_single_line(&self) -> bool {
  526        matches!(self, Self::SingleLine { .. })
  527    }
  528
  529    #[inline]
  530    fn is_minimap(&self) -> bool {
  531        matches!(self, Self::Minimap { .. })
  532    }
  533}
  534
  535#[derive(Copy, Clone, Debug)]
  536pub enum SoftWrap {
  537    /// Prefer not to wrap at all.
  538    ///
  539    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  540    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  541    GitDiff,
  542    /// Prefer a single line generally, unless an overly long line is encountered.
  543    None,
  544    /// Soft wrap lines that exceed the editor width.
  545    EditorWidth,
  546    /// Soft wrap lines at the preferred line length.
  547    Column(u32),
  548    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  549    Bounded(u32),
  550}
  551
  552#[derive(Clone)]
  553pub struct EditorStyle {
  554    pub background: Hsla,
  555    pub border: Hsla,
  556    pub local_player: PlayerColor,
  557    pub text: TextStyle,
  558    pub scrollbar_width: Pixels,
  559    pub syntax: Arc<SyntaxTheme>,
  560    pub status: StatusColors,
  561    pub inlay_hints_style: HighlightStyle,
  562    pub edit_prediction_styles: EditPredictionStyles,
  563    pub unnecessary_code_fade: f32,
  564    pub show_underlines: bool,
  565}
  566
  567impl Default for EditorStyle {
  568    fn default() -> Self {
  569        Self {
  570            background: Hsla::default(),
  571            border: Hsla::default(),
  572            local_player: PlayerColor::default(),
  573            text: TextStyle::default(),
  574            scrollbar_width: Pixels::default(),
  575            syntax: Default::default(),
  576            // HACK: Status colors don't have a real default.
  577            // We should look into removing the status colors from the editor
  578            // style and retrieve them directly from the theme.
  579            status: StatusColors::dark(),
  580            inlay_hints_style: HighlightStyle::default(),
  581            edit_prediction_styles: EditPredictionStyles {
  582                insertion: HighlightStyle::default(),
  583                whitespace: HighlightStyle::default(),
  584            },
  585            unnecessary_code_fade: Default::default(),
  586            show_underlines: true,
  587        }
  588    }
  589}
  590
  591pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  592    let show_background = language_settings::language_settings(None, None, cx)
  593        .inlay_hints
  594        .show_background;
  595
  596    let mut style = cx.theme().syntax().get("hint");
  597
  598    if style.color.is_none() {
  599        style.color = Some(cx.theme().status().hint);
  600    }
  601
  602    if !show_background {
  603        style.background_color = None;
  604        return style;
  605    }
  606
  607    if style.background_color.is_none() {
  608        style.background_color = Some(cx.theme().status().hint_background);
  609    }
  610
  611    style
  612}
  613
  614pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  615    EditPredictionStyles {
  616        insertion: HighlightStyle {
  617            color: Some(cx.theme().status().predictive),
  618            ..HighlightStyle::default()
  619        },
  620        whitespace: HighlightStyle {
  621            background_color: Some(cx.theme().status().created_background),
  622            ..HighlightStyle::default()
  623        },
  624    }
  625}
  626
  627type CompletionId = usize;
  628
  629pub(crate) enum EditDisplayMode {
  630    TabAccept,
  631    DiffPopover,
  632    Inline,
  633}
  634
  635enum EditPrediction {
  636    Edit {
  637        edits: Vec<(Range<Anchor>, String)>,
  638        edit_preview: Option<EditPreview>,
  639        display_mode: EditDisplayMode,
  640        snapshot: BufferSnapshot,
  641    },
  642    /// Move to a specific location in the active editor
  643    MoveWithin {
  644        target: Anchor,
  645        snapshot: BufferSnapshot,
  646    },
  647    /// Move to a specific location in a different editor (not the active one)
  648    MoveOutside {
  649        target: language::Anchor,
  650        snapshot: BufferSnapshot,
  651    },
  652}
  653
  654struct EditPredictionState {
  655    inlay_ids: Vec<InlayId>,
  656    completion: EditPrediction,
  657    completion_id: Option<SharedString>,
  658    invalidation_range: Option<Range<Anchor>>,
  659}
  660
  661enum EditPredictionSettings {
  662    Disabled,
  663    Enabled {
  664        show_in_menu: bool,
  665        preview_requires_modifier: bool,
  666    },
  667}
  668
  669enum EditPredictionHighlight {}
  670
  671#[derive(Debug, Clone)]
  672struct InlineDiagnostic {
  673    message: SharedString,
  674    group_id: usize,
  675    is_primary: bool,
  676    start: Point,
  677    severity: lsp::DiagnosticSeverity,
  678}
  679
  680pub enum MenuEditPredictionsPolicy {
  681    Never,
  682    ByProvider,
  683}
  684
  685pub enum EditPredictionPreview {
  686    /// Modifier is not pressed
  687    Inactive { released_too_fast: bool },
  688    /// Modifier pressed
  689    Active {
  690        since: Instant,
  691        previous_scroll_position: Option<ScrollAnchor>,
  692    },
  693}
  694
  695impl EditPredictionPreview {
  696    pub fn released_too_fast(&self) -> bool {
  697        match self {
  698            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  699            EditPredictionPreview::Active { .. } => false,
  700        }
  701    }
  702
  703    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  704        if let EditPredictionPreview::Active {
  705            previous_scroll_position,
  706            ..
  707        } = self
  708        {
  709            *previous_scroll_position = scroll_position;
  710        }
  711    }
  712}
  713
  714pub struct ContextMenuOptions {
  715    pub min_entries_visible: usize,
  716    pub max_entries_visible: usize,
  717    pub placement: Option<ContextMenuPlacement>,
  718}
  719
  720#[derive(Debug, Clone, PartialEq, Eq)]
  721pub enum ContextMenuPlacement {
  722    Above,
  723    Below,
  724}
  725
  726#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  727struct EditorActionId(usize);
  728
  729impl EditorActionId {
  730    pub fn post_inc(&mut self) -> Self {
  731        let answer = self.0;
  732
  733        *self = Self(answer + 1);
  734
  735        Self(answer)
  736    }
  737}
  738
  739// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  740// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  741
  742type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  743type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  744
  745#[derive(Default)]
  746struct ScrollbarMarkerState {
  747    scrollbar_size: Size<Pixels>,
  748    dirty: bool,
  749    markers: Arc<[PaintQuad]>,
  750    pending_refresh: Option<Task<Result<()>>>,
  751}
  752
  753impl ScrollbarMarkerState {
  754    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  755        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  756    }
  757}
  758
  759#[derive(Clone, Copy, PartialEq, Eq)]
  760pub enum MinimapVisibility {
  761    Disabled,
  762    Enabled {
  763        /// The configuration currently present in the users settings.
  764        setting_configuration: bool,
  765        /// Whether to override the currently set visibility from the users setting.
  766        toggle_override: bool,
  767    },
  768}
  769
  770impl MinimapVisibility {
  771    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  772        if mode.is_full() {
  773            Self::Enabled {
  774                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  775                toggle_override: false,
  776            }
  777        } else {
  778            Self::Disabled
  779        }
  780    }
  781
  782    fn hidden(&self) -> Self {
  783        match *self {
  784            Self::Enabled {
  785                setting_configuration,
  786                ..
  787            } => Self::Enabled {
  788                setting_configuration,
  789                toggle_override: setting_configuration,
  790            },
  791            Self::Disabled => Self::Disabled,
  792        }
  793    }
  794
  795    fn disabled(&self) -> bool {
  796        matches!(*self, Self::Disabled)
  797    }
  798
  799    fn settings_visibility(&self) -> bool {
  800        match *self {
  801            Self::Enabled {
  802                setting_configuration,
  803                ..
  804            } => setting_configuration,
  805            _ => false,
  806        }
  807    }
  808
  809    fn visible(&self) -> bool {
  810        match *self {
  811            Self::Enabled {
  812                setting_configuration,
  813                toggle_override,
  814            } => setting_configuration ^ toggle_override,
  815            _ => false,
  816        }
  817    }
  818
  819    fn toggle_visibility(&self) -> Self {
  820        match *self {
  821            Self::Enabled {
  822                toggle_override,
  823                setting_configuration,
  824            } => Self::Enabled {
  825                setting_configuration,
  826                toggle_override: !toggle_override,
  827            },
  828            Self::Disabled => Self::Disabled,
  829        }
  830    }
  831}
  832
  833#[derive(Clone, Debug)]
  834struct RunnableTasks {
  835    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  836    offset: multi_buffer::Anchor,
  837    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  838    column: u32,
  839    // Values of all named captures, including those starting with '_'
  840    extra_variables: HashMap<String, String>,
  841    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  842    context_range: Range<BufferOffset>,
  843}
  844
  845impl RunnableTasks {
  846    fn resolve<'a>(
  847        &'a self,
  848        cx: &'a task::TaskContext,
  849    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  850        self.templates.iter().filter_map(|(kind, template)| {
  851            template
  852                .resolve_task(&kind.to_id_base(), cx)
  853                .map(|task| (kind.clone(), task))
  854        })
  855    }
  856}
  857
  858#[derive(Clone)]
  859pub struct ResolvedTasks {
  860    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  861    position: Anchor,
  862}
  863
  864#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  865struct BufferOffset(usize);
  866
  867/// Addons allow storing per-editor state in other crates (e.g. Vim)
  868pub trait Addon: 'static {
  869    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  870
  871    fn render_buffer_header_controls(
  872        &self,
  873        _: &ExcerptInfo,
  874        _: &Window,
  875        _: &App,
  876    ) -> Option<AnyElement> {
  877        None
  878    }
  879
  880    fn to_any(&self) -> &dyn std::any::Any;
  881
  882    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  883        None
  884    }
  885}
  886
  887struct ChangeLocation {
  888    current: Option<Vec<Anchor>>,
  889    original: Vec<Anchor>,
  890}
  891impl ChangeLocation {
  892    fn locations(&self) -> &[Anchor] {
  893        self.current.as_ref().unwrap_or(&self.original)
  894    }
  895}
  896
  897/// A set of caret positions, registered when the editor was edited.
  898pub struct ChangeList {
  899    changes: Vec<ChangeLocation>,
  900    /// Currently "selected" change.
  901    position: Option<usize>,
  902}
  903
  904impl ChangeList {
  905    pub fn new() -> Self {
  906        Self {
  907            changes: Vec::new(),
  908            position: None,
  909        }
  910    }
  911
  912    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  913    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  914    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  915        if self.changes.is_empty() {
  916            return None;
  917        }
  918
  919        let prev = self.position.unwrap_or(self.changes.len());
  920        let next = if direction == Direction::Prev {
  921            prev.saturating_sub(count)
  922        } else {
  923            (prev + count).min(self.changes.len() - 1)
  924        };
  925        self.position = Some(next);
  926        self.changes.get(next).map(|change| change.locations())
  927    }
  928
  929    /// Adds a new change to the list, resetting the change list position.
  930    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  931        self.position.take();
  932        if let Some(last) = self.changes.last_mut()
  933            && group
  934        {
  935            last.current = Some(new_positions)
  936        } else {
  937            self.changes.push(ChangeLocation {
  938                original: new_positions,
  939                current: None,
  940            });
  941        }
  942    }
  943
  944    pub fn last(&self) -> Option<&[Anchor]> {
  945        self.changes.last().map(|change| change.locations())
  946    }
  947
  948    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  949        self.changes.last().map(|change| change.original.as_slice())
  950    }
  951
  952    pub fn invert_last_group(&mut self) {
  953        if let Some(last) = self.changes.last_mut()
  954            && let Some(current) = last.current.as_mut()
  955        {
  956            mem::swap(&mut last.original, current);
  957        }
  958    }
  959}
  960
  961#[derive(Clone)]
  962struct InlineBlamePopoverState {
  963    scroll_handle: ScrollHandle,
  964    commit_message: Option<ParsedCommitMessage>,
  965    markdown: Entity<Markdown>,
  966}
  967
  968struct InlineBlamePopover {
  969    position: gpui::Point<Pixels>,
  970    hide_task: Option<Task<()>>,
  971    popover_bounds: Option<Bounds<Pixels>>,
  972    popover_state: InlineBlamePopoverState,
  973    keyboard_grace: bool,
  974}
  975
  976enum SelectionDragState {
  977    /// State when no drag related activity is detected.
  978    None,
  979    /// State when the mouse is down on a selection that is about to be dragged.
  980    ReadyToDrag {
  981        selection: Selection<Anchor>,
  982        click_position: gpui::Point<Pixels>,
  983        mouse_down_time: Instant,
  984    },
  985    /// State when the mouse is dragging the selection in the editor.
  986    Dragging {
  987        selection: Selection<Anchor>,
  988        drop_cursor: Selection<Anchor>,
  989        hide_drop_cursor: bool,
  990    },
  991}
  992
  993enum ColumnarSelectionState {
  994    FromMouse {
  995        selection_tail: Anchor,
  996        display_point: Option<DisplayPoint>,
  997    },
  998    FromSelection {
  999        selection_tail: Anchor,
 1000    },
 1001}
 1002
 1003/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1004/// a breakpoint on them.
 1005#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1006struct PhantomBreakpointIndicator {
 1007    display_row: DisplayRow,
 1008    /// There's a small debounce between hovering over the line and showing the indicator.
 1009    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1010    is_active: bool,
 1011    collides_with_existing_breakpoint: bool,
 1012}
 1013
 1014/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1015///
 1016/// See the [module level documentation](self) for more information.
 1017pub struct Editor {
 1018    focus_handle: FocusHandle,
 1019    last_focused_descendant: Option<WeakFocusHandle>,
 1020    /// The text buffer being edited
 1021    buffer: Entity<MultiBuffer>,
 1022    /// Map of how text in the buffer should be displayed.
 1023    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1024    pub display_map: Entity<DisplayMap>,
 1025    placeholder_display_map: Option<Entity<DisplayMap>>,
 1026    pub selections: SelectionsCollection,
 1027    pub scroll_manager: ScrollManager,
 1028    /// When inline assist editors are linked, they all render cursors because
 1029    /// typing enters text into each of them, even the ones that aren't focused.
 1030    pub(crate) show_cursor_when_unfocused: bool,
 1031    columnar_selection_state: Option<ColumnarSelectionState>,
 1032    add_selections_state: Option<AddSelectionsState>,
 1033    select_next_state: Option<SelectNextState>,
 1034    select_prev_state: Option<SelectNextState>,
 1035    selection_history: SelectionHistory,
 1036    defer_selection_effects: bool,
 1037    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1038    autoclose_regions: Vec<AutocloseRegion>,
 1039    snippet_stack: InvalidationStack<SnippetState>,
 1040    select_syntax_node_history: SelectSyntaxNodeHistory,
 1041    ime_transaction: Option<TransactionId>,
 1042    pub diagnostics_max_severity: DiagnosticSeverity,
 1043    active_diagnostics: ActiveDiagnostic,
 1044    show_inline_diagnostics: bool,
 1045    inline_diagnostics_update: Task<()>,
 1046    inline_diagnostics_enabled: bool,
 1047    diagnostics_enabled: bool,
 1048    word_completions_enabled: bool,
 1049    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1050    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1051    hard_wrap: Option<usize>,
 1052    project: Option<Entity<Project>>,
 1053    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1054    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1055    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1056    blink_manager: Entity<BlinkManager>,
 1057    show_cursor_names: bool,
 1058    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1059    pub show_local_selections: bool,
 1060    mode: EditorMode,
 1061    show_breadcrumbs: bool,
 1062    show_gutter: bool,
 1063    show_scrollbars: ScrollbarAxes,
 1064    minimap_visibility: MinimapVisibility,
 1065    offset_content: bool,
 1066    disable_expand_excerpt_buttons: bool,
 1067    show_line_numbers: Option<bool>,
 1068    use_relative_line_numbers: Option<bool>,
 1069    show_git_diff_gutter: Option<bool>,
 1070    show_code_actions: Option<bool>,
 1071    show_runnables: Option<bool>,
 1072    show_breakpoints: Option<bool>,
 1073    show_wrap_guides: Option<bool>,
 1074    show_indent_guides: Option<bool>,
 1075    highlight_order: usize,
 1076    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1077    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1078    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1079    scrollbar_marker_state: ScrollbarMarkerState,
 1080    active_indent_guides_state: ActiveIndentGuidesState,
 1081    nav_history: Option<ItemNavHistory>,
 1082    context_menu: RefCell<Option<CodeContextMenu>>,
 1083    context_menu_options: Option<ContextMenuOptions>,
 1084    mouse_context_menu: Option<MouseContextMenu>,
 1085    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1086    inline_blame_popover: Option<InlineBlamePopover>,
 1087    inline_blame_popover_show_task: Option<Task<()>>,
 1088    signature_help_state: SignatureHelpState,
 1089    auto_signature_help: Option<bool>,
 1090    find_all_references_task_sources: Vec<Anchor>,
 1091    next_completion_id: CompletionId,
 1092    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1093    code_actions_task: Option<Task<Result<()>>>,
 1094    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1096    document_highlights_task: Option<Task<()>>,
 1097    linked_editing_range_task: Option<Task<Option<()>>>,
 1098    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1099    pending_rename: Option<RenameState>,
 1100    searchable: bool,
 1101    cursor_shape: CursorShape,
 1102    current_line_highlight: Option<CurrentLineHighlight>,
 1103    collapse_matches: bool,
 1104    autoindent_mode: Option<AutoindentMode>,
 1105    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1106    input_enabled: bool,
 1107    use_modal_editing: bool,
 1108    read_only: bool,
 1109    leader_id: Option<CollaboratorId>,
 1110    remote_id: Option<ViewId>,
 1111    pub hover_state: HoverState,
 1112    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1113    gutter_hovered: bool,
 1114    hovered_link_state: Option<HoveredLinkState>,
 1115    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1116    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1117    active_edit_prediction: Option<EditPredictionState>,
 1118    /// Used to prevent flickering as the user types while the menu is open
 1119    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1120    edit_prediction_settings: EditPredictionSettings,
 1121    edit_predictions_hidden_for_vim_mode: bool,
 1122    show_edit_predictions_override: Option<bool>,
 1123    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1124    edit_prediction_preview: EditPredictionPreview,
 1125    edit_prediction_indent_conflict: bool,
 1126    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1127    inlay_hint_cache: InlayHintCache,
 1128    next_inlay_id: u32,
 1129    next_color_inlay_id: u32,
 1130    _subscriptions: Vec<Subscription>,
 1131    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1132    gutter_dimensions: GutterDimensions,
 1133    style: Option<EditorStyle>,
 1134    text_style_refinement: Option<TextStyleRefinement>,
 1135    next_editor_action_id: EditorActionId,
 1136    editor_actions: Rc<
 1137        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1138    >,
 1139    use_autoclose: bool,
 1140    use_auto_surround: bool,
 1141    auto_replace_emoji_shortcode: bool,
 1142    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1143    show_git_blame_gutter: bool,
 1144    show_git_blame_inline: bool,
 1145    show_git_blame_inline_delay_task: Option<Task<()>>,
 1146    git_blame_inline_enabled: bool,
 1147    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1148    serialize_dirty_buffers: bool,
 1149    show_selection_menu: Option<bool>,
 1150    blame: Option<Entity<GitBlame>>,
 1151    blame_subscription: Option<Subscription>,
 1152    custom_context_menu: Option<
 1153        Box<
 1154            dyn 'static
 1155                + Fn(
 1156                    &mut Self,
 1157                    DisplayPoint,
 1158                    &mut Window,
 1159                    &mut Context<Self>,
 1160                ) -> Option<Entity<ui::ContextMenu>>,
 1161        >,
 1162    >,
 1163    last_bounds: Option<Bounds<Pixels>>,
 1164    last_position_map: Option<Rc<PositionMap>>,
 1165    expect_bounds_change: Option<Bounds<Pixels>>,
 1166    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1167    tasks_update_task: Option<Task<()>>,
 1168    breakpoint_store: Option<Entity<BreakpointStore>>,
 1169    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1170    hovered_diff_hunk_row: Option<DisplayRow>,
 1171    pull_diagnostics_task: Task<()>,
 1172    in_project_search: bool,
 1173    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1174    breadcrumb_header: Option<String>,
 1175    focused_block: Option<FocusedBlock>,
 1176    next_scroll_position: NextScrollCursorCenterTopBottom,
 1177    addons: HashMap<TypeId, Box<dyn Addon>>,
 1178    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1179    load_diff_task: Option<Shared<Task<()>>>,
 1180    /// Whether we are temporarily displaying a diff other than git's
 1181    temporary_diff_override: bool,
 1182    selection_mark_mode: bool,
 1183    toggle_fold_multiple_buffers: Task<()>,
 1184    _scroll_cursor_center_top_bottom_task: Task<()>,
 1185    serialize_selections: Task<()>,
 1186    serialize_folds: Task<()>,
 1187    mouse_cursor_hidden: bool,
 1188    minimap: Option<Entity<Self>>,
 1189    hide_mouse_mode: HideMouseMode,
 1190    pub change_list: ChangeList,
 1191    inline_value_cache: InlineValueCache,
 1192    selection_drag_state: SelectionDragState,
 1193    colors: Option<LspColorData>,
 1194    post_scroll_update: Task<()>,
 1195    refresh_colors_task: Task<()>,
 1196    folding_newlines: Task<()>,
 1197    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1198}
 1199
 1200#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1201enum NextScrollCursorCenterTopBottom {
 1202    #[default]
 1203    Center,
 1204    Top,
 1205    Bottom,
 1206}
 1207
 1208impl NextScrollCursorCenterTopBottom {
 1209    fn next(&self) -> Self {
 1210        match self {
 1211            Self::Center => Self::Top,
 1212            Self::Top => Self::Bottom,
 1213            Self::Bottom => Self::Center,
 1214        }
 1215    }
 1216}
 1217
 1218#[derive(Clone)]
 1219pub struct EditorSnapshot {
 1220    pub mode: EditorMode,
 1221    show_gutter: bool,
 1222    show_line_numbers: Option<bool>,
 1223    show_git_diff_gutter: Option<bool>,
 1224    show_code_actions: Option<bool>,
 1225    show_runnables: Option<bool>,
 1226    show_breakpoints: Option<bool>,
 1227    git_blame_gutter_max_author_length: Option<usize>,
 1228    pub display_snapshot: DisplaySnapshot,
 1229    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1230    is_focused: bool,
 1231    scroll_anchor: ScrollAnchor,
 1232    ongoing_scroll: OngoingScroll,
 1233    current_line_highlight: CurrentLineHighlight,
 1234    gutter_hovered: bool,
 1235}
 1236
 1237#[derive(Default, Debug, Clone, Copy)]
 1238pub struct GutterDimensions {
 1239    pub left_padding: Pixels,
 1240    pub right_padding: Pixels,
 1241    pub width: Pixels,
 1242    pub margin: Pixels,
 1243    pub git_blame_entries_width: Option<Pixels>,
 1244}
 1245
 1246impl GutterDimensions {
 1247    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1248        Self {
 1249            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1250            ..Default::default()
 1251        }
 1252    }
 1253
 1254    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1255        -cx.text_system().descent(font_id, font_size)
 1256    }
 1257    /// The full width of the space taken up by the gutter.
 1258    pub fn full_width(&self) -> Pixels {
 1259        self.margin + self.width
 1260    }
 1261
 1262    /// The width of the space reserved for the fold indicators,
 1263    /// use alongside 'justify_end' and `gutter_width` to
 1264    /// right align content with the line numbers
 1265    pub fn fold_area_width(&self) -> Pixels {
 1266        self.margin + self.right_padding
 1267    }
 1268}
 1269
 1270struct CharacterDimensions {
 1271    em_width: Pixels,
 1272    em_advance: Pixels,
 1273    line_height: Pixels,
 1274}
 1275
 1276#[derive(Debug)]
 1277pub struct RemoteSelection {
 1278    pub replica_id: ReplicaId,
 1279    pub selection: Selection<Anchor>,
 1280    pub cursor_shape: CursorShape,
 1281    pub collaborator_id: CollaboratorId,
 1282    pub line_mode: bool,
 1283    pub user_name: Option<SharedString>,
 1284    pub color: PlayerColor,
 1285}
 1286
 1287#[derive(Clone, Debug)]
 1288struct SelectionHistoryEntry {
 1289    selections: Arc<[Selection<Anchor>]>,
 1290    select_next_state: Option<SelectNextState>,
 1291    select_prev_state: Option<SelectNextState>,
 1292    add_selections_state: Option<AddSelectionsState>,
 1293}
 1294
 1295#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1296enum SelectionHistoryMode {
 1297    Normal,
 1298    Undoing,
 1299    Redoing,
 1300    Skipping,
 1301}
 1302
 1303#[derive(Clone, PartialEq, Eq, Hash)]
 1304struct HoveredCursor {
 1305    replica_id: ReplicaId,
 1306    selection_id: usize,
 1307}
 1308
 1309impl Default for SelectionHistoryMode {
 1310    fn default() -> Self {
 1311        Self::Normal
 1312    }
 1313}
 1314
 1315#[derive(Debug)]
 1316/// SelectionEffects controls the side-effects of updating the selection.
 1317///
 1318/// The default behaviour does "what you mostly want":
 1319/// - it pushes to the nav history if the cursor moved by >10 lines
 1320/// - it re-triggers completion requests
 1321/// - it scrolls to fit
 1322///
 1323/// You might want to modify these behaviours. For example when doing a "jump"
 1324/// like go to definition, we always want to add to nav history; but when scrolling
 1325/// in vim mode we never do.
 1326///
 1327/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1328/// move.
 1329#[derive(Clone)]
 1330pub struct SelectionEffects {
 1331    nav_history: Option<bool>,
 1332    completions: bool,
 1333    scroll: Option<Autoscroll>,
 1334}
 1335
 1336impl Default for SelectionEffects {
 1337    fn default() -> Self {
 1338        Self {
 1339            nav_history: None,
 1340            completions: true,
 1341            scroll: Some(Autoscroll::fit()),
 1342        }
 1343    }
 1344}
 1345impl SelectionEffects {
 1346    pub fn scroll(scroll: Autoscroll) -> Self {
 1347        Self {
 1348            scroll: Some(scroll),
 1349            ..Default::default()
 1350        }
 1351    }
 1352
 1353    pub fn no_scroll() -> Self {
 1354        Self {
 1355            scroll: None,
 1356            ..Default::default()
 1357        }
 1358    }
 1359
 1360    pub fn completions(self, completions: bool) -> Self {
 1361        Self {
 1362            completions,
 1363            ..self
 1364        }
 1365    }
 1366
 1367    pub fn nav_history(self, nav_history: bool) -> Self {
 1368        Self {
 1369            nav_history: Some(nav_history),
 1370            ..self
 1371        }
 1372    }
 1373}
 1374
 1375struct DeferredSelectionEffectsState {
 1376    changed: bool,
 1377    effects: SelectionEffects,
 1378    old_cursor_position: Anchor,
 1379    history_entry: SelectionHistoryEntry,
 1380}
 1381
 1382#[derive(Default)]
 1383struct SelectionHistory {
 1384    #[allow(clippy::type_complexity)]
 1385    selections_by_transaction:
 1386        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1387    mode: SelectionHistoryMode,
 1388    undo_stack: VecDeque<SelectionHistoryEntry>,
 1389    redo_stack: VecDeque<SelectionHistoryEntry>,
 1390}
 1391
 1392impl SelectionHistory {
 1393    #[track_caller]
 1394    fn insert_transaction(
 1395        &mut self,
 1396        transaction_id: TransactionId,
 1397        selections: Arc<[Selection<Anchor>]>,
 1398    ) {
 1399        if selections.is_empty() {
 1400            log::error!(
 1401                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1402                std::panic::Location::caller()
 1403            );
 1404            return;
 1405        }
 1406        self.selections_by_transaction
 1407            .insert(transaction_id, (selections, None));
 1408    }
 1409
 1410    #[allow(clippy::type_complexity)]
 1411    fn transaction(
 1412        &self,
 1413        transaction_id: TransactionId,
 1414    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1415        self.selections_by_transaction.get(&transaction_id)
 1416    }
 1417
 1418    #[allow(clippy::type_complexity)]
 1419    fn transaction_mut(
 1420        &mut self,
 1421        transaction_id: TransactionId,
 1422    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1423        self.selections_by_transaction.get_mut(&transaction_id)
 1424    }
 1425
 1426    fn push(&mut self, entry: SelectionHistoryEntry) {
 1427        if !entry.selections.is_empty() {
 1428            match self.mode {
 1429                SelectionHistoryMode::Normal => {
 1430                    self.push_undo(entry);
 1431                    self.redo_stack.clear();
 1432                }
 1433                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1434                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1435                SelectionHistoryMode::Skipping => {}
 1436            }
 1437        }
 1438    }
 1439
 1440    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1441        if self
 1442            .undo_stack
 1443            .back()
 1444            .is_none_or(|e| e.selections != entry.selections)
 1445        {
 1446            self.undo_stack.push_back(entry);
 1447            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1448                self.undo_stack.pop_front();
 1449            }
 1450        }
 1451    }
 1452
 1453    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1454        if self
 1455            .redo_stack
 1456            .back()
 1457            .is_none_or(|e| e.selections != entry.selections)
 1458        {
 1459            self.redo_stack.push_back(entry);
 1460            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1461                self.redo_stack.pop_front();
 1462            }
 1463        }
 1464    }
 1465}
 1466
 1467#[derive(Clone, Copy)]
 1468pub struct RowHighlightOptions {
 1469    pub autoscroll: bool,
 1470    pub include_gutter: bool,
 1471}
 1472
 1473impl Default for RowHighlightOptions {
 1474    fn default() -> Self {
 1475        Self {
 1476            autoscroll: Default::default(),
 1477            include_gutter: true,
 1478        }
 1479    }
 1480}
 1481
 1482struct RowHighlight {
 1483    index: usize,
 1484    range: Range<Anchor>,
 1485    color: Hsla,
 1486    options: RowHighlightOptions,
 1487    type_id: TypeId,
 1488}
 1489
 1490#[derive(Clone, Debug)]
 1491struct AddSelectionsState {
 1492    groups: Vec<AddSelectionsGroup>,
 1493}
 1494
 1495#[derive(Clone, Debug)]
 1496struct AddSelectionsGroup {
 1497    above: bool,
 1498    stack: Vec<usize>,
 1499}
 1500
 1501#[derive(Clone)]
 1502struct SelectNextState {
 1503    query: AhoCorasick,
 1504    wordwise: bool,
 1505    done: bool,
 1506}
 1507
 1508impl std::fmt::Debug for SelectNextState {
 1509    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1510        f.debug_struct(std::any::type_name::<Self>())
 1511            .field("wordwise", &self.wordwise)
 1512            .field("done", &self.done)
 1513            .finish()
 1514    }
 1515}
 1516
 1517#[derive(Debug)]
 1518struct AutocloseRegion {
 1519    selection_id: usize,
 1520    range: Range<Anchor>,
 1521    pair: BracketPair,
 1522}
 1523
 1524#[derive(Debug)]
 1525struct SnippetState {
 1526    ranges: Vec<Vec<Range<Anchor>>>,
 1527    active_index: usize,
 1528    choices: Vec<Option<Vec<String>>>,
 1529}
 1530
 1531#[doc(hidden)]
 1532pub struct RenameState {
 1533    pub range: Range<Anchor>,
 1534    pub old_name: Arc<str>,
 1535    pub editor: Entity<Editor>,
 1536    block_id: CustomBlockId,
 1537}
 1538
 1539struct InvalidationStack<T>(Vec<T>);
 1540
 1541struct RegisteredEditPredictionProvider {
 1542    provider: Arc<dyn EditPredictionProviderHandle>,
 1543    _subscription: Subscription,
 1544}
 1545
 1546#[derive(Debug, PartialEq, Eq)]
 1547pub struct ActiveDiagnosticGroup {
 1548    pub active_range: Range<Anchor>,
 1549    pub active_message: String,
 1550    pub group_id: usize,
 1551    pub blocks: HashSet<CustomBlockId>,
 1552}
 1553
 1554#[derive(Debug, PartialEq, Eq)]
 1555
 1556pub(crate) enum ActiveDiagnostic {
 1557    None,
 1558    All,
 1559    Group(ActiveDiagnosticGroup),
 1560}
 1561
 1562#[derive(Serialize, Deserialize, Clone, Debug)]
 1563pub struct ClipboardSelection {
 1564    /// The number of bytes in this selection.
 1565    pub len: usize,
 1566    /// Whether this was a full-line selection.
 1567    pub is_entire_line: bool,
 1568    /// The indentation of the first line when this content was originally copied.
 1569    pub first_line_indent: u32,
 1570}
 1571
 1572// selections, scroll behavior, was newest selection reversed
 1573type SelectSyntaxNodeHistoryState = (
 1574    Box<[Selection<usize>]>,
 1575    SelectSyntaxNodeScrollBehavior,
 1576    bool,
 1577);
 1578
 1579#[derive(Default)]
 1580struct SelectSyntaxNodeHistory {
 1581    stack: Vec<SelectSyntaxNodeHistoryState>,
 1582    // disable temporarily to allow changing selections without losing the stack
 1583    pub disable_clearing: bool,
 1584}
 1585
 1586impl SelectSyntaxNodeHistory {
 1587    pub fn try_clear(&mut self) {
 1588        if !self.disable_clearing {
 1589            self.stack.clear();
 1590        }
 1591    }
 1592
 1593    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1594        self.stack.push(selection);
 1595    }
 1596
 1597    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1598        self.stack.pop()
 1599    }
 1600}
 1601
 1602enum SelectSyntaxNodeScrollBehavior {
 1603    CursorTop,
 1604    FitSelection,
 1605    CursorBottom,
 1606}
 1607
 1608#[derive(Debug)]
 1609pub(crate) struct NavigationData {
 1610    cursor_anchor: Anchor,
 1611    cursor_position: Point,
 1612    scroll_anchor: ScrollAnchor,
 1613    scroll_top_row: u32,
 1614}
 1615
 1616#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1617pub enum GotoDefinitionKind {
 1618    Symbol,
 1619    Declaration,
 1620    Type,
 1621    Implementation,
 1622}
 1623
 1624#[derive(Debug, Clone)]
 1625enum InlayHintRefreshReason {
 1626    ModifiersChanged(bool),
 1627    Toggle(bool),
 1628    SettingsChange(InlayHintSettings),
 1629    NewLinesShown,
 1630    BufferEdited(HashSet<Arc<Language>>),
 1631    RefreshRequested,
 1632    ExcerptsRemoved(Vec<ExcerptId>),
 1633}
 1634
 1635impl InlayHintRefreshReason {
 1636    fn description(&self) -> &'static str {
 1637        match self {
 1638            Self::ModifiersChanged(_) => "modifiers changed",
 1639            Self::Toggle(_) => "toggle",
 1640            Self::SettingsChange(_) => "settings change",
 1641            Self::NewLinesShown => "new lines shown",
 1642            Self::BufferEdited(_) => "buffer edited",
 1643            Self::RefreshRequested => "refresh requested",
 1644            Self::ExcerptsRemoved(_) => "excerpts removed",
 1645        }
 1646    }
 1647}
 1648
 1649pub enum FormatTarget {
 1650    Buffers(HashSet<Entity<Buffer>>),
 1651    Ranges(Vec<Range<MultiBufferPoint>>),
 1652}
 1653
 1654pub(crate) struct FocusedBlock {
 1655    id: BlockId,
 1656    focus_handle: WeakFocusHandle,
 1657}
 1658
 1659#[derive(Clone)]
 1660enum JumpData {
 1661    MultiBufferRow {
 1662        row: MultiBufferRow,
 1663        line_offset_from_top: u32,
 1664    },
 1665    MultiBufferPoint {
 1666        excerpt_id: ExcerptId,
 1667        position: Point,
 1668        anchor: text::Anchor,
 1669        line_offset_from_top: u32,
 1670    },
 1671}
 1672
 1673pub enum MultibufferSelectionMode {
 1674    First,
 1675    All,
 1676}
 1677
 1678#[derive(Clone, Copy, Debug, Default)]
 1679pub struct RewrapOptions {
 1680    pub override_language_settings: bool,
 1681    pub preserve_existing_whitespace: bool,
 1682}
 1683
 1684impl Editor {
 1685    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1689    }
 1690
 1691    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1692        let buffer = cx.new(|cx| Buffer::local("", cx));
 1693        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1694        Self::new(EditorMode::full(), buffer, None, window, cx)
 1695    }
 1696
 1697    pub fn auto_height(
 1698        min_lines: usize,
 1699        max_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: Some(max_lines),
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1718    /// The editor grows as tall as needed to fit its content.
 1719    pub fn auto_height_unbounded(
 1720        min_lines: usize,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| Buffer::local("", cx));
 1725        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1726        Self::new(
 1727            EditorMode::AutoHeight {
 1728                min_lines,
 1729                max_lines: None,
 1730            },
 1731            buffer,
 1732            None,
 1733            window,
 1734            cx,
 1735        )
 1736    }
 1737
 1738    pub fn for_buffer(
 1739        buffer: Entity<Buffer>,
 1740        project: Option<Entity<Project>>,
 1741        window: &mut Window,
 1742        cx: &mut Context<Self>,
 1743    ) -> Self {
 1744        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1745        Self::new(EditorMode::full(), buffer, project, window, cx)
 1746    }
 1747
 1748    pub fn for_multibuffer(
 1749        buffer: Entity<MultiBuffer>,
 1750        project: Option<Entity<Project>>,
 1751        window: &mut Window,
 1752        cx: &mut Context<Self>,
 1753    ) -> Self {
 1754        Self::new(EditorMode::full(), buffer, project, window, cx)
 1755    }
 1756
 1757    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1758        let mut clone = Self::new(
 1759            self.mode.clone(),
 1760            self.buffer.clone(),
 1761            self.project.clone(),
 1762            window,
 1763            cx,
 1764        );
 1765        self.display_map.update(cx, |display_map, cx| {
 1766            let snapshot = display_map.snapshot(cx);
 1767            clone.display_map.update(cx, |display_map, cx| {
 1768                display_map.set_state(&snapshot, cx);
 1769            });
 1770        });
 1771        clone.folds_did_change(cx);
 1772        clone.selections.clone_state(&self.selections);
 1773        clone.scroll_manager.clone_state(&self.scroll_manager);
 1774        clone.searchable = self.searchable;
 1775        clone.read_only = self.read_only;
 1776        clone
 1777    }
 1778
 1779    pub fn new(
 1780        mode: EditorMode,
 1781        buffer: Entity<MultiBuffer>,
 1782        project: Option<Entity<Project>>,
 1783        window: &mut Window,
 1784        cx: &mut Context<Self>,
 1785    ) -> Self {
 1786        Editor::new_internal(mode, buffer, project, None, window, cx)
 1787    }
 1788
 1789    fn new_internal(
 1790        mode: EditorMode,
 1791        multi_buffer: Entity<MultiBuffer>,
 1792        project: Option<Entity<Project>>,
 1793        display_map: Option<Entity<DisplayMap>>,
 1794        window: &mut Window,
 1795        cx: &mut Context<Self>,
 1796    ) -> Self {
 1797        debug_assert!(
 1798            display_map.is_none() || mode.is_minimap(),
 1799            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1800        );
 1801
 1802        let full_mode = mode.is_full();
 1803        let is_minimap = mode.is_minimap();
 1804        let diagnostics_max_severity = if full_mode {
 1805            EditorSettings::get_global(cx)
 1806                .diagnostics_max_severity
 1807                .unwrap_or(DiagnosticSeverity::Hint)
 1808        } else {
 1809            DiagnosticSeverity::Off
 1810        };
 1811        let style = window.text_style();
 1812        let font_size = style.font_size.to_pixels(window.rem_size());
 1813        let editor = cx.entity().downgrade();
 1814        let fold_placeholder = FoldPlaceholder {
 1815            constrain_width: false,
 1816            render: Arc::new(move |fold_id, fold_range, cx| {
 1817                let editor = editor.clone();
 1818                div()
 1819                    .id(fold_id)
 1820                    .bg(cx.theme().colors().ghost_element_background)
 1821                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1822                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1823                    .rounded_xs()
 1824                    .size_full()
 1825                    .cursor_pointer()
 1826                    .child("")
 1827                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1828                    .on_click(move |_, _window, cx| {
 1829                        editor
 1830                            .update(cx, |editor, cx| {
 1831                                editor.unfold_ranges(
 1832                                    &[fold_range.start..fold_range.end],
 1833                                    true,
 1834                                    false,
 1835                                    cx,
 1836                                );
 1837                                cx.stop_propagation();
 1838                            })
 1839                            .ok();
 1840                    })
 1841                    .into_any()
 1842            }),
 1843            merge_adjacent: true,
 1844            ..FoldPlaceholder::default()
 1845        };
 1846        let display_map = display_map.unwrap_or_else(|| {
 1847            cx.new(|cx| {
 1848                DisplayMap::new(
 1849                    multi_buffer.clone(),
 1850                    style.font(),
 1851                    font_size,
 1852                    None,
 1853                    FILE_HEADER_HEIGHT,
 1854                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1855                    fold_placeholder,
 1856                    diagnostics_max_severity,
 1857                    cx,
 1858                )
 1859            })
 1860        });
 1861
 1862        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1863
 1864        let blink_manager = cx.new(|cx| {
 1865            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1866            if is_minimap {
 1867                blink_manager.disable(cx);
 1868            }
 1869            blink_manager
 1870        });
 1871
 1872        let soft_wrap_mode_override =
 1873            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1874
 1875        let mut project_subscriptions = Vec::new();
 1876        if full_mode && let Some(project) = project.as_ref() {
 1877            project_subscriptions.push(cx.subscribe_in(
 1878                project,
 1879                window,
 1880                |editor, _, event, window, cx| match event {
 1881                    project::Event::RefreshCodeLens => {
 1882                        // we always query lens with actions, without storing them, always refreshing them
 1883                    }
 1884                    project::Event::RefreshInlayHints => {
 1885                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1886                    }
 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                        editor.registered_buffers.clear();
 1892                        editor.register_visible_buffers(cx);
 1893                    }
 1894                    project::Event::LanguageServerAdded(..) => {
 1895                        if editor.tasks_update_task.is_none() {
 1896                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1897                        }
 1898                    }
 1899                    project::Event::SnippetEdit(id, snippet_edits) => {
 1900                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1901                            let focus_handle = editor.focus_handle(cx);
 1902                            if focus_handle.is_focused(window) {
 1903                                let snapshot = buffer.read(cx).snapshot();
 1904                                for (range, snippet) in snippet_edits {
 1905                                    let editor_range =
 1906                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1907                                    editor
 1908                                        .insert_snippet(
 1909                                            &[editor_range],
 1910                                            snippet.clone(),
 1911                                            window,
 1912                                            cx,
 1913                                        )
 1914                                        .ok();
 1915                                }
 1916                            }
 1917                        }
 1918                    }
 1919                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1920                        let buffer_id = *buffer_id;
 1921                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1922                            let registered = editor.register_buffer(buffer_id, cx);
 1923                            if registered {
 1924                                editor.update_lsp_data(Some(buffer_id), window, cx);
 1925                                editor.refresh_inlay_hints(
 1926                                    InlayHintRefreshReason::RefreshRequested,
 1927                                    cx,
 1928                                );
 1929                                refresh_linked_ranges(editor, window, cx);
 1930                                editor.refresh_code_actions(window, cx);
 1931                                editor.refresh_document_highlights(cx);
 1932                            }
 1933                        }
 1934                    }
 1935
 1936                    project::Event::EntryRenamed(transaction) => {
 1937                        let Some(workspace) = editor.workspace() else {
 1938                            return;
 1939                        };
 1940                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1941                        else {
 1942                            return;
 1943                        };
 1944                        if active_editor.entity_id() == cx.entity_id() {
 1945                            let edited_buffers_already_open = {
 1946                                let other_editors: Vec<Entity<Editor>> = workspace
 1947                                    .read(cx)
 1948                                    .panes()
 1949                                    .iter()
 1950                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1951                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1952                                    .collect();
 1953
 1954                                transaction.0.keys().all(|buffer| {
 1955                                    other_editors.iter().any(|editor| {
 1956                                        let multi_buffer = editor.read(cx).buffer();
 1957                                        multi_buffer.read(cx).is_singleton()
 1958                                            && multi_buffer.read(cx).as_singleton().map_or(
 1959                                                false,
 1960                                                |singleton| {
 1961                                                    singleton.entity_id() == buffer.entity_id()
 1962                                                },
 1963                                            )
 1964                                    })
 1965                                })
 1966                            };
 1967
 1968                            if !edited_buffers_already_open {
 1969                                let workspace = workspace.downgrade();
 1970                                let transaction = transaction.clone();
 1971                                cx.defer_in(window, move |_, window, cx| {
 1972                                    cx.spawn_in(window, async move |editor, cx| {
 1973                                        Self::open_project_transaction(
 1974                                            &editor,
 1975                                            workspace,
 1976                                            transaction,
 1977                                            "Rename".to_string(),
 1978                                            cx,
 1979                                        )
 1980                                        .await
 1981                                        .ok()
 1982                                    })
 1983                                    .detach();
 1984                                });
 1985                            }
 1986                        }
 1987                    }
 1988
 1989                    _ => {}
 1990                },
 1991            ));
 1992            if let Some(task_inventory) = project
 1993                .read(cx)
 1994                .task_store()
 1995                .read(cx)
 1996                .task_inventory()
 1997                .cloned()
 1998            {
 1999                project_subscriptions.push(cx.observe_in(
 2000                    &task_inventory,
 2001                    window,
 2002                    |editor, _, window, cx| {
 2003                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2004                    },
 2005                ));
 2006            };
 2007
 2008            project_subscriptions.push(cx.subscribe_in(
 2009                &project.read(cx).breakpoint_store(),
 2010                window,
 2011                |editor, _, event, window, cx| match event {
 2012                    BreakpointStoreEvent::ClearDebugLines => {
 2013                        editor.clear_row_highlights::<ActiveDebugLine>();
 2014                        editor.refresh_inline_values(cx);
 2015                    }
 2016                    BreakpointStoreEvent::SetDebugLine => {
 2017                        if editor.go_to_active_debug_line(window, cx) {
 2018                            cx.stop_propagation();
 2019                        }
 2020
 2021                        editor.refresh_inline_values(cx);
 2022                    }
 2023                    _ => {}
 2024                },
 2025            ));
 2026            let git_store = project.read(cx).git_store().clone();
 2027            let project = project.clone();
 2028            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2029                if let GitStoreEvent::RepositoryUpdated(
 2030                    _,
 2031                    RepositoryEvent::Updated {
 2032                        new_instance: true, ..
 2033                    },
 2034                    _,
 2035                ) = event
 2036                {
 2037                    this.load_diff_task = Some(
 2038                        update_uncommitted_diff_for_buffer(
 2039                            cx.entity(),
 2040                            &project,
 2041                            this.buffer.read(cx).all_buffers(),
 2042                            this.buffer.clone(),
 2043                            cx,
 2044                        )
 2045                        .shared(),
 2046                    );
 2047                }
 2048            }));
 2049        }
 2050
 2051        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2052
 2053        let inlay_hint_settings =
 2054            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2055        let focus_handle = cx.focus_handle();
 2056        if !is_minimap {
 2057            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2058                .detach();
 2059            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2060                .detach();
 2061            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2062                .detach();
 2063            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2064                .detach();
 2065            cx.observe_pending_input(window, Self::observe_pending_input)
 2066                .detach();
 2067        }
 2068
 2069        let show_indent_guides =
 2070            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2071                Some(false)
 2072            } else {
 2073                None
 2074            };
 2075
 2076        let breakpoint_store = match (&mode, project.as_ref()) {
 2077            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2078            _ => None,
 2079        };
 2080
 2081        let mut code_action_providers = Vec::new();
 2082        let mut load_uncommitted_diff = None;
 2083        if let Some(project) = project.clone() {
 2084            load_uncommitted_diff = Some(
 2085                update_uncommitted_diff_for_buffer(
 2086                    cx.entity(),
 2087                    &project,
 2088                    multi_buffer.read(cx).all_buffers(),
 2089                    multi_buffer.clone(),
 2090                    cx,
 2091                )
 2092                .shared(),
 2093            );
 2094            code_action_providers.push(Rc::new(project) as Rc<_>);
 2095        }
 2096
 2097        let mut editor = Self {
 2098            focus_handle,
 2099            show_cursor_when_unfocused: false,
 2100            last_focused_descendant: None,
 2101            buffer: multi_buffer.clone(),
 2102            display_map: display_map.clone(),
 2103            placeholder_display_map: None,
 2104            selections,
 2105            scroll_manager: ScrollManager::new(cx),
 2106            columnar_selection_state: None,
 2107            add_selections_state: None,
 2108            select_next_state: None,
 2109            select_prev_state: None,
 2110            selection_history: SelectionHistory::default(),
 2111            defer_selection_effects: false,
 2112            deferred_selection_effects_state: None,
 2113            autoclose_regions: Vec::new(),
 2114            snippet_stack: InvalidationStack::default(),
 2115            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2116            ime_transaction: None,
 2117            active_diagnostics: ActiveDiagnostic::None,
 2118            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2119            inline_diagnostics_update: Task::ready(()),
 2120            inline_diagnostics: Vec::new(),
 2121            soft_wrap_mode_override,
 2122            diagnostics_max_severity,
 2123            hard_wrap: None,
 2124            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2125            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2126            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2127            project,
 2128            blink_manager: blink_manager.clone(),
 2129            show_local_selections: true,
 2130            show_scrollbars: ScrollbarAxes {
 2131                horizontal: full_mode,
 2132                vertical: full_mode,
 2133            },
 2134            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2135            offset_content: !matches!(mode, EditorMode::SingleLine),
 2136            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2137            show_gutter: full_mode,
 2138            show_line_numbers: (!full_mode).then_some(false),
 2139            use_relative_line_numbers: None,
 2140            disable_expand_excerpt_buttons: !full_mode,
 2141            show_git_diff_gutter: None,
 2142            show_code_actions: None,
 2143            show_runnables: None,
 2144            show_breakpoints: None,
 2145            show_wrap_guides: None,
 2146            show_indent_guides,
 2147            highlight_order: 0,
 2148            highlighted_rows: HashMap::default(),
 2149            background_highlights: HashMap::default(),
 2150            gutter_highlights: HashMap::default(),
 2151            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2152            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2153            nav_history: None,
 2154            context_menu: RefCell::new(None),
 2155            context_menu_options: None,
 2156            mouse_context_menu: None,
 2157            completion_tasks: Vec::new(),
 2158            inline_blame_popover: None,
 2159            inline_blame_popover_show_task: None,
 2160            signature_help_state: SignatureHelpState::default(),
 2161            auto_signature_help: None,
 2162            find_all_references_task_sources: Vec::new(),
 2163            next_completion_id: 0,
 2164            next_inlay_id: 0,
 2165            code_action_providers,
 2166            available_code_actions: None,
 2167            code_actions_task: None,
 2168            quick_selection_highlight_task: None,
 2169            debounced_selection_highlight_task: None,
 2170            document_highlights_task: None,
 2171            linked_editing_range_task: None,
 2172            pending_rename: None,
 2173            searchable: !is_minimap,
 2174            cursor_shape: EditorSettings::get_global(cx)
 2175                .cursor_shape
 2176                .unwrap_or_default(),
 2177            current_line_highlight: None,
 2178            autoindent_mode: Some(AutoindentMode::EachLine),
 2179            collapse_matches: false,
 2180            workspace: None,
 2181            input_enabled: !is_minimap,
 2182            use_modal_editing: full_mode,
 2183            read_only: is_minimap,
 2184            use_autoclose: true,
 2185            use_auto_surround: true,
 2186            auto_replace_emoji_shortcode: false,
 2187            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2188            leader_id: None,
 2189            remote_id: None,
 2190            hover_state: HoverState::default(),
 2191            pending_mouse_down: None,
 2192            hovered_link_state: None,
 2193            edit_prediction_provider: None,
 2194            active_edit_prediction: None,
 2195            stale_edit_prediction_in_menu: None,
 2196            edit_prediction_preview: EditPredictionPreview::Inactive {
 2197                released_too_fast: false,
 2198            },
 2199            inline_diagnostics_enabled: full_mode,
 2200            diagnostics_enabled: full_mode,
 2201            word_completions_enabled: full_mode,
 2202            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2203            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2204            gutter_hovered: false,
 2205            pixel_position_of_newest_cursor: None,
 2206            last_bounds: None,
 2207            last_position_map: None,
 2208            expect_bounds_change: None,
 2209            gutter_dimensions: GutterDimensions::default(),
 2210            style: None,
 2211            show_cursor_names: false,
 2212            hovered_cursors: HashMap::default(),
 2213            next_editor_action_id: EditorActionId::default(),
 2214            editor_actions: Rc::default(),
 2215            edit_predictions_hidden_for_vim_mode: false,
 2216            show_edit_predictions_override: None,
 2217            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2218            edit_prediction_settings: EditPredictionSettings::Disabled,
 2219            edit_prediction_indent_conflict: false,
 2220            edit_prediction_requires_modifier_in_indent_conflict: true,
 2221            custom_context_menu: None,
 2222            show_git_blame_gutter: false,
 2223            show_git_blame_inline: false,
 2224            show_selection_menu: None,
 2225            show_git_blame_inline_delay_task: None,
 2226            git_blame_inline_enabled: full_mode
 2227                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2228            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2229            serialize_dirty_buffers: !is_minimap
 2230                && ProjectSettings::get_global(cx)
 2231                    .session
 2232                    .restore_unsaved_buffers,
 2233            blame: None,
 2234            blame_subscription: None,
 2235            tasks: BTreeMap::default(),
 2236
 2237            breakpoint_store,
 2238            gutter_breakpoint_indicator: (None, None),
 2239            hovered_diff_hunk_row: None,
 2240            _subscriptions: (!is_minimap)
 2241                .then(|| {
 2242                    vec![
 2243                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2244                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2245                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2246                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2247                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2248                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2249                        cx.observe_window_activation(window, |editor, window, cx| {
 2250                            let active = window.is_window_active();
 2251                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2252                                if active {
 2253                                    blink_manager.enable(cx);
 2254                                } else {
 2255                                    blink_manager.disable(cx);
 2256                                }
 2257                            });
 2258                            if active {
 2259                                editor.show_mouse_cursor(cx);
 2260                            }
 2261                        }),
 2262                    ]
 2263                })
 2264                .unwrap_or_default(),
 2265            tasks_update_task: None,
 2266            pull_diagnostics_task: Task::ready(()),
 2267            colors: None,
 2268            refresh_colors_task: Task::ready(()),
 2269            next_color_inlay_id: 0,
 2270            post_scroll_update: Task::ready(()),
 2271            linked_edit_ranges: Default::default(),
 2272            in_project_search: false,
 2273            previous_search_ranges: None,
 2274            breadcrumb_header: None,
 2275            focused_block: None,
 2276            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2277            addons: HashMap::default(),
 2278            registered_buffers: HashMap::default(),
 2279            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2280            selection_mark_mode: false,
 2281            toggle_fold_multiple_buffers: Task::ready(()),
 2282            serialize_selections: Task::ready(()),
 2283            serialize_folds: Task::ready(()),
 2284            text_style_refinement: None,
 2285            load_diff_task: load_uncommitted_diff,
 2286            temporary_diff_override: false,
 2287            mouse_cursor_hidden: false,
 2288            minimap: None,
 2289            hide_mouse_mode: EditorSettings::get_global(cx)
 2290                .hide_mouse
 2291                .unwrap_or_default(),
 2292            change_list: ChangeList::new(),
 2293            mode,
 2294            selection_drag_state: SelectionDragState::None,
 2295            folding_newlines: Task::ready(()),
 2296            lookup_key: None,
 2297        };
 2298
 2299        if is_minimap {
 2300            return editor;
 2301        }
 2302
 2303        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2304            editor
 2305                ._subscriptions
 2306                .push(cx.observe(breakpoints, |_, _, cx| {
 2307                    cx.notify();
 2308                }));
 2309        }
 2310        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2311        editor._subscriptions.extend(project_subscriptions);
 2312
 2313        editor._subscriptions.push(cx.subscribe_in(
 2314            &cx.entity(),
 2315            window,
 2316            |editor, _, e: &EditorEvent, window, cx| match e {
 2317                EditorEvent::ScrollPositionChanged { local, .. } => {
 2318                    if *local {
 2319                        let new_anchor = editor.scroll_manager.anchor();
 2320                        let snapshot = editor.snapshot(window, cx);
 2321                        editor.update_restoration_data(cx, move |data| {
 2322                            data.scroll_position = (
 2323                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2324                                new_anchor.offset,
 2325                            );
 2326                        });
 2327                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2328                        editor.inline_blame_popover.take();
 2329                    }
 2330                }
 2331                EditorEvent::Edited { .. } => {
 2332                    if !vim_enabled(cx) {
 2333                        let display_map = editor.display_snapshot(cx);
 2334                        let selections = editor.selections.all_adjusted_display(&display_map);
 2335                        let pop_state = editor
 2336                            .change_list
 2337                            .last()
 2338                            .map(|previous| {
 2339                                previous.len() == selections.len()
 2340                                    && previous.iter().enumerate().all(|(ix, p)| {
 2341                                        p.to_display_point(&display_map).row()
 2342                                            == selections[ix].head().row()
 2343                                    })
 2344                            })
 2345                            .unwrap_or(false);
 2346                        let new_positions = selections
 2347                            .into_iter()
 2348                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2349                            .collect();
 2350                        editor
 2351                            .change_list
 2352                            .push_to_change_list(pop_state, new_positions);
 2353                    }
 2354                }
 2355                _ => (),
 2356            },
 2357        ));
 2358
 2359        if let Some(dap_store) = editor
 2360            .project
 2361            .as_ref()
 2362            .map(|project| project.read(cx).dap_store())
 2363        {
 2364            let weak_editor = cx.weak_entity();
 2365
 2366            editor
 2367                ._subscriptions
 2368                .push(
 2369                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2370                        let session_entity = cx.entity();
 2371                        weak_editor
 2372                            .update(cx, |editor, cx| {
 2373                                editor._subscriptions.push(
 2374                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2375                                );
 2376                            })
 2377                            .ok();
 2378                    }),
 2379                );
 2380
 2381            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2382                editor
 2383                    ._subscriptions
 2384                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2385            }
 2386        }
 2387
 2388        // skip adding the initial selection to selection history
 2389        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2390        editor.end_selection(window, cx);
 2391        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2392
 2393        editor.scroll_manager.show_scrollbars(window, cx);
 2394        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2395
 2396        if full_mode {
 2397            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2398            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2399
 2400            if editor.git_blame_inline_enabled {
 2401                editor.start_git_blame_inline(false, window, cx);
 2402            }
 2403
 2404            editor.go_to_active_debug_line(window, cx);
 2405
 2406            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2407                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2408            }
 2409
 2410            editor.minimap =
 2411                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2412            editor.colors = Some(LspColorData::new(cx));
 2413            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2414        }
 2415
 2416        editor
 2417    }
 2418
 2419    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2420        self.selections.display_map(cx)
 2421    }
 2422
 2423    pub fn deploy_mouse_context_menu(
 2424        &mut self,
 2425        position: gpui::Point<Pixels>,
 2426        context_menu: Entity<ContextMenu>,
 2427        window: &mut Window,
 2428        cx: &mut Context<Self>,
 2429    ) {
 2430        self.mouse_context_menu = Some(MouseContextMenu::new(
 2431            self,
 2432            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2433            context_menu,
 2434            window,
 2435            cx,
 2436        ));
 2437    }
 2438
 2439    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2440        self.mouse_context_menu
 2441            .as_ref()
 2442            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2443    }
 2444
 2445    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2446        if self
 2447            .selections
 2448            .pending_anchor()
 2449            .is_some_and(|pending_selection| {
 2450                let snapshot = self.buffer().read(cx).snapshot(cx);
 2451                pending_selection.range().includes(range, &snapshot)
 2452            })
 2453        {
 2454            return true;
 2455        }
 2456
 2457        self.selections
 2458            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2459            .into_iter()
 2460            .any(|selection| {
 2461                // This is needed to cover a corner case, if we just check for an existing
 2462                // selection in the fold range, having a cursor at the start of the fold
 2463                // marks it as selected. Non-empty selections don't cause this.
 2464                let length = selection.end - selection.start;
 2465                length > 0
 2466            })
 2467    }
 2468
 2469    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2470        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2471    }
 2472
 2473    fn key_context_internal(
 2474        &self,
 2475        has_active_edit_prediction: bool,
 2476        window: &Window,
 2477        cx: &App,
 2478    ) -> KeyContext {
 2479        let mut key_context = KeyContext::new_with_defaults();
 2480        key_context.add("Editor");
 2481        let mode = match self.mode {
 2482            EditorMode::SingleLine => "single_line",
 2483            EditorMode::AutoHeight { .. } => "auto_height",
 2484            EditorMode::Minimap { .. } => "minimap",
 2485            EditorMode::Full { .. } => "full",
 2486        };
 2487
 2488        if EditorSettings::jupyter_enabled(cx) {
 2489            key_context.add("jupyter");
 2490        }
 2491
 2492        key_context.set("mode", mode);
 2493        if self.pending_rename.is_some() {
 2494            key_context.add("renaming");
 2495        }
 2496
 2497        match self.context_menu.borrow().as_ref() {
 2498            Some(CodeContextMenu::Completions(menu)) => {
 2499                if menu.visible() {
 2500                    key_context.add("menu");
 2501                    key_context.add("showing_completions");
 2502                }
 2503            }
 2504            Some(CodeContextMenu::CodeActions(menu)) => {
 2505                if menu.visible() {
 2506                    key_context.add("menu");
 2507                    key_context.add("showing_code_actions")
 2508                }
 2509            }
 2510            None => {}
 2511        }
 2512
 2513        if self.signature_help_state.has_multiple_signatures() {
 2514            key_context.add("showing_signature_help");
 2515        }
 2516
 2517        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2518        if !self.focus_handle(cx).contains_focused(window, cx)
 2519            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2520        {
 2521            for addon in self.addons.values() {
 2522                addon.extend_key_context(&mut key_context, cx)
 2523            }
 2524        }
 2525
 2526        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2527            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2528                Some(
 2529                    file.full_path(cx)
 2530                        .extension()?
 2531                        .to_string_lossy()
 2532                        .into_owned(),
 2533                )
 2534            }) {
 2535                key_context.set("extension", extension);
 2536            }
 2537        } else {
 2538            key_context.add("multibuffer");
 2539        }
 2540
 2541        if has_active_edit_prediction {
 2542            if self.edit_prediction_in_conflict() {
 2543                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2544            } else {
 2545                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2546                key_context.add("copilot_suggestion");
 2547            }
 2548        }
 2549
 2550        if self.selection_mark_mode {
 2551            key_context.add("selection_mode");
 2552        }
 2553
 2554        key_context
 2555    }
 2556
 2557    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2558        self.last_bounds.as_ref()
 2559    }
 2560
 2561    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2562        if self.mouse_cursor_hidden {
 2563            self.mouse_cursor_hidden = false;
 2564            cx.notify();
 2565        }
 2566    }
 2567
 2568    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2569        let hide_mouse_cursor = match origin {
 2570            HideMouseCursorOrigin::TypingAction => {
 2571                matches!(
 2572                    self.hide_mouse_mode,
 2573                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2574                )
 2575            }
 2576            HideMouseCursorOrigin::MovementAction => {
 2577                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2578            }
 2579        };
 2580        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2581            self.mouse_cursor_hidden = hide_mouse_cursor;
 2582            cx.notify();
 2583        }
 2584    }
 2585
 2586    pub fn edit_prediction_in_conflict(&self) -> bool {
 2587        if !self.show_edit_predictions_in_menu() {
 2588            return false;
 2589        }
 2590
 2591        let showing_completions = self
 2592            .context_menu
 2593            .borrow()
 2594            .as_ref()
 2595            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2596
 2597        showing_completions
 2598            || self.edit_prediction_requires_modifier()
 2599            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2600            // bindings to insert tab characters.
 2601            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2602    }
 2603
 2604    pub fn accept_edit_prediction_keybind(
 2605        &self,
 2606        accept_partial: bool,
 2607        window: &Window,
 2608        cx: &App,
 2609    ) -> AcceptEditPredictionBinding {
 2610        let key_context = self.key_context_internal(true, window, cx);
 2611        let in_conflict = self.edit_prediction_in_conflict();
 2612
 2613        let bindings = if accept_partial {
 2614            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2615        } else {
 2616            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2617        };
 2618
 2619        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2620        // just the first one.
 2621        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2622            !in_conflict
 2623                || binding
 2624                    .keystrokes()
 2625                    .first()
 2626                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2627        }))
 2628    }
 2629
 2630    pub fn new_file(
 2631        workspace: &mut Workspace,
 2632        _: &workspace::NewFile,
 2633        window: &mut Window,
 2634        cx: &mut Context<Workspace>,
 2635    ) {
 2636        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2637            "Failed to create buffer",
 2638            window,
 2639            cx,
 2640            |e, _, _| match e.error_code() {
 2641                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2642                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2643                e.error_tag("required").unwrap_or("the latest version")
 2644            )),
 2645                _ => None,
 2646            },
 2647        );
 2648    }
 2649
 2650    pub fn new_in_workspace(
 2651        workspace: &mut Workspace,
 2652        window: &mut Window,
 2653        cx: &mut Context<Workspace>,
 2654    ) -> Task<Result<Entity<Editor>>> {
 2655        let project = workspace.project().clone();
 2656        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2657
 2658        cx.spawn_in(window, async move |workspace, cx| {
 2659            let buffer = create.await?;
 2660            workspace.update_in(cx, |workspace, window, cx| {
 2661                let editor =
 2662                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2663                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2664                editor
 2665            })
 2666        })
 2667    }
 2668
 2669    fn new_file_vertical(
 2670        workspace: &mut Workspace,
 2671        _: &workspace::NewFileSplitVertical,
 2672        window: &mut Window,
 2673        cx: &mut Context<Workspace>,
 2674    ) {
 2675        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2676    }
 2677
 2678    fn new_file_horizontal(
 2679        workspace: &mut Workspace,
 2680        _: &workspace::NewFileSplitHorizontal,
 2681        window: &mut Window,
 2682        cx: &mut Context<Workspace>,
 2683    ) {
 2684        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2685    }
 2686
 2687    fn new_file_split(
 2688        workspace: &mut Workspace,
 2689        action: &workspace::NewFileSplit,
 2690        window: &mut Window,
 2691        cx: &mut Context<Workspace>,
 2692    ) {
 2693        Self::new_file_in_direction(workspace, action.0, window, cx)
 2694    }
 2695
 2696    fn new_file_in_direction(
 2697        workspace: &mut Workspace,
 2698        direction: SplitDirection,
 2699        window: &mut Window,
 2700        cx: &mut Context<Workspace>,
 2701    ) {
 2702        let project = workspace.project().clone();
 2703        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2704
 2705        cx.spawn_in(window, async move |workspace, cx| {
 2706            let buffer = create.await?;
 2707            workspace.update_in(cx, move |workspace, window, cx| {
 2708                workspace.split_item(
 2709                    direction,
 2710                    Box::new(
 2711                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2712                    ),
 2713                    window,
 2714                    cx,
 2715                )
 2716            })?;
 2717            anyhow::Ok(())
 2718        })
 2719        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2720            match e.error_code() {
 2721                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2722                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2723                e.error_tag("required").unwrap_or("the latest version")
 2724            )),
 2725                _ => None,
 2726            }
 2727        });
 2728    }
 2729
 2730    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2731        self.leader_id
 2732    }
 2733
 2734    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2735        &self.buffer
 2736    }
 2737
 2738    pub fn project(&self) -> Option<&Entity<Project>> {
 2739        self.project.as_ref()
 2740    }
 2741
 2742    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2743        self.workspace.as_ref()?.0.upgrade()
 2744    }
 2745
 2746    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2747        self.buffer().read(cx).title(cx)
 2748    }
 2749
 2750    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2751        let git_blame_gutter_max_author_length = self
 2752            .render_git_blame_gutter(cx)
 2753            .then(|| {
 2754                if let Some(blame) = self.blame.as_ref() {
 2755                    let max_author_length =
 2756                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2757                    Some(max_author_length)
 2758                } else {
 2759                    None
 2760                }
 2761            })
 2762            .flatten();
 2763
 2764        EditorSnapshot {
 2765            mode: self.mode.clone(),
 2766            show_gutter: self.show_gutter,
 2767            show_line_numbers: self.show_line_numbers,
 2768            show_git_diff_gutter: self.show_git_diff_gutter,
 2769            show_code_actions: self.show_code_actions,
 2770            show_runnables: self.show_runnables,
 2771            show_breakpoints: self.show_breakpoints,
 2772            git_blame_gutter_max_author_length,
 2773            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2774            placeholder_display_snapshot: self
 2775                .placeholder_display_map
 2776                .as_ref()
 2777                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2778            scroll_anchor: self.scroll_manager.anchor(),
 2779            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2780            is_focused: self.focus_handle.is_focused(window),
 2781            current_line_highlight: self
 2782                .current_line_highlight
 2783                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2784            gutter_hovered: self.gutter_hovered,
 2785        }
 2786    }
 2787
 2788    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2789        self.buffer.read(cx).language_at(point, cx)
 2790    }
 2791
 2792    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2793        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2794    }
 2795
 2796    pub fn active_excerpt(
 2797        &self,
 2798        cx: &App,
 2799    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2800        self.buffer
 2801            .read(cx)
 2802            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2803    }
 2804
 2805    pub fn mode(&self) -> &EditorMode {
 2806        &self.mode
 2807    }
 2808
 2809    pub fn set_mode(&mut self, mode: EditorMode) {
 2810        self.mode = mode;
 2811    }
 2812
 2813    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2814        self.collaboration_hub.as_deref()
 2815    }
 2816
 2817    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2818        self.collaboration_hub = Some(hub);
 2819    }
 2820
 2821    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2822        self.in_project_search = in_project_search;
 2823    }
 2824
 2825    pub fn set_custom_context_menu(
 2826        &mut self,
 2827        f: impl 'static
 2828        + Fn(
 2829            &mut Self,
 2830            DisplayPoint,
 2831            &mut Window,
 2832            &mut Context<Self>,
 2833        ) -> Option<Entity<ui::ContextMenu>>,
 2834    ) {
 2835        self.custom_context_menu = Some(Box::new(f))
 2836    }
 2837
 2838    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2839        self.completion_provider = provider;
 2840    }
 2841
 2842    #[cfg(any(test, feature = "test-support"))]
 2843    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2844        self.completion_provider.clone()
 2845    }
 2846
 2847    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2848        self.semantics_provider.clone()
 2849    }
 2850
 2851    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2852        self.semantics_provider = provider;
 2853    }
 2854
 2855    pub fn set_edit_prediction_provider<T>(
 2856        &mut self,
 2857        provider: Option<Entity<T>>,
 2858        window: &mut Window,
 2859        cx: &mut Context<Self>,
 2860    ) where
 2861        T: EditPredictionProvider,
 2862    {
 2863        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2864            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2865                if this.focus_handle.is_focused(window) {
 2866                    this.update_visible_edit_prediction(window, cx);
 2867                }
 2868            }),
 2869            provider: Arc::new(provider),
 2870        });
 2871        self.update_edit_prediction_settings(cx);
 2872        self.refresh_edit_prediction(false, false, window, cx);
 2873    }
 2874
 2875    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2876        self.placeholder_display_map
 2877            .as_ref()
 2878            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2879    }
 2880
 2881    pub fn set_placeholder_text(
 2882        &mut self,
 2883        placeholder_text: &str,
 2884        window: &mut Window,
 2885        cx: &mut Context<Self>,
 2886    ) {
 2887        let multibuffer = cx
 2888            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2889
 2890        let style = window.text_style();
 2891
 2892        self.placeholder_display_map = Some(cx.new(|cx| {
 2893            DisplayMap::new(
 2894                multibuffer,
 2895                style.font(),
 2896                style.font_size.to_pixels(window.rem_size()),
 2897                None,
 2898                FILE_HEADER_HEIGHT,
 2899                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2900                Default::default(),
 2901                DiagnosticSeverity::Off,
 2902                cx,
 2903            )
 2904        }));
 2905        cx.notify();
 2906    }
 2907
 2908    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2909        self.cursor_shape = cursor_shape;
 2910
 2911        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2912        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2913
 2914        cx.notify();
 2915    }
 2916
 2917    pub fn set_current_line_highlight(
 2918        &mut self,
 2919        current_line_highlight: Option<CurrentLineHighlight>,
 2920    ) {
 2921        self.current_line_highlight = current_line_highlight;
 2922    }
 2923
 2924    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2925        self.collapse_matches = collapse_matches;
 2926    }
 2927
 2928    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2929        if self.collapse_matches {
 2930            return range.start..range.start;
 2931        }
 2932        range.clone()
 2933    }
 2934
 2935    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2936        if self.display_map.read(cx).clip_at_line_ends != clip {
 2937            self.display_map
 2938                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2939        }
 2940    }
 2941
 2942    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2943        self.input_enabled = input_enabled;
 2944    }
 2945
 2946    pub fn set_edit_predictions_hidden_for_vim_mode(
 2947        &mut self,
 2948        hidden: bool,
 2949        window: &mut Window,
 2950        cx: &mut Context<Self>,
 2951    ) {
 2952        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2953            self.edit_predictions_hidden_for_vim_mode = hidden;
 2954            if hidden {
 2955                self.update_visible_edit_prediction(window, cx);
 2956            } else {
 2957                self.refresh_edit_prediction(true, false, window, cx);
 2958            }
 2959        }
 2960    }
 2961
 2962    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2963        self.menu_edit_predictions_policy = value;
 2964    }
 2965
 2966    pub fn set_autoindent(&mut self, autoindent: bool) {
 2967        if autoindent {
 2968            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2969        } else {
 2970            self.autoindent_mode = None;
 2971        }
 2972    }
 2973
 2974    pub fn read_only(&self, cx: &App) -> bool {
 2975        self.read_only || self.buffer.read(cx).read_only()
 2976    }
 2977
 2978    pub fn set_read_only(&mut self, read_only: bool) {
 2979        self.read_only = read_only;
 2980    }
 2981
 2982    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2983        self.use_autoclose = autoclose;
 2984    }
 2985
 2986    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2987        self.use_auto_surround = auto_surround;
 2988    }
 2989
 2990    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2991        self.auto_replace_emoji_shortcode = auto_replace;
 2992    }
 2993
 2994    pub fn toggle_edit_predictions(
 2995        &mut self,
 2996        _: &ToggleEditPrediction,
 2997        window: &mut Window,
 2998        cx: &mut Context<Self>,
 2999    ) {
 3000        if self.show_edit_predictions_override.is_some() {
 3001            self.set_show_edit_predictions(None, window, cx);
 3002        } else {
 3003            let show_edit_predictions = !self.edit_predictions_enabled();
 3004            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3005        }
 3006    }
 3007
 3008    pub fn set_show_edit_predictions(
 3009        &mut self,
 3010        show_edit_predictions: Option<bool>,
 3011        window: &mut Window,
 3012        cx: &mut Context<Self>,
 3013    ) {
 3014        self.show_edit_predictions_override = show_edit_predictions;
 3015        self.update_edit_prediction_settings(cx);
 3016
 3017        if let Some(false) = show_edit_predictions {
 3018            self.discard_edit_prediction(false, cx);
 3019        } else {
 3020            self.refresh_edit_prediction(false, true, window, cx);
 3021        }
 3022    }
 3023
 3024    fn edit_predictions_disabled_in_scope(
 3025        &self,
 3026        buffer: &Entity<Buffer>,
 3027        buffer_position: language::Anchor,
 3028        cx: &App,
 3029    ) -> bool {
 3030        let snapshot = buffer.read(cx).snapshot();
 3031        let settings = snapshot.settings_at(buffer_position, cx);
 3032
 3033        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3034            return false;
 3035        };
 3036
 3037        scope.override_name().is_some_and(|scope_name| {
 3038            settings
 3039                .edit_predictions_disabled_in
 3040                .iter()
 3041                .any(|s| s == scope_name)
 3042        })
 3043    }
 3044
 3045    pub fn set_use_modal_editing(&mut self, to: bool) {
 3046        self.use_modal_editing = to;
 3047    }
 3048
 3049    pub fn use_modal_editing(&self) -> bool {
 3050        self.use_modal_editing
 3051    }
 3052
 3053    fn selections_did_change(
 3054        &mut self,
 3055        local: bool,
 3056        old_cursor_position: &Anchor,
 3057        effects: SelectionEffects,
 3058        window: &mut Window,
 3059        cx: &mut Context<Self>,
 3060    ) {
 3061        window.invalidate_character_coordinates();
 3062
 3063        // Copy selections to primary selection buffer
 3064        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3065        if local {
 3066            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3067            let buffer_handle = self.buffer.read(cx).read(cx);
 3068
 3069            let mut text = String::new();
 3070            for (index, selection) in selections.iter().enumerate() {
 3071                let text_for_selection = buffer_handle
 3072                    .text_for_range(selection.start..selection.end)
 3073                    .collect::<String>();
 3074
 3075                text.push_str(&text_for_selection);
 3076                if index != selections.len() - 1 {
 3077                    text.push('\n');
 3078                }
 3079            }
 3080
 3081            if !text.is_empty() {
 3082                cx.write_to_primary(ClipboardItem::new_string(text));
 3083            }
 3084        }
 3085
 3086        let selection_anchors = self.selections.disjoint_anchors_arc();
 3087
 3088        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3089            self.buffer.update(cx, |buffer, cx| {
 3090                buffer.set_active_selections(
 3091                    &selection_anchors,
 3092                    self.selections.line_mode(),
 3093                    self.cursor_shape,
 3094                    cx,
 3095                )
 3096            });
 3097        }
 3098        let display_map = self
 3099            .display_map
 3100            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3101        let buffer = display_map.buffer_snapshot();
 3102        if self.selections.count() == 1 {
 3103            self.add_selections_state = None;
 3104        }
 3105        self.select_next_state = None;
 3106        self.select_prev_state = None;
 3107        self.select_syntax_node_history.try_clear();
 3108        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3109        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3110        self.take_rename(false, window, cx);
 3111
 3112        let newest_selection = self.selections.newest_anchor();
 3113        let new_cursor_position = newest_selection.head();
 3114        let selection_start = newest_selection.start;
 3115
 3116        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3117            self.push_to_nav_history(
 3118                *old_cursor_position,
 3119                Some(new_cursor_position.to_point(buffer)),
 3120                false,
 3121                effects.nav_history == Some(true),
 3122                cx,
 3123            );
 3124        }
 3125
 3126        if local {
 3127            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3128                self.register_buffer(buffer_id, cx);
 3129            }
 3130
 3131            let mut context_menu = self.context_menu.borrow_mut();
 3132            let completion_menu = match context_menu.as_ref() {
 3133                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3134                Some(CodeContextMenu::CodeActions(_)) => {
 3135                    *context_menu = None;
 3136                    None
 3137                }
 3138                None => None,
 3139            };
 3140            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3141            drop(context_menu);
 3142
 3143            if effects.completions
 3144                && let Some(completion_position) = completion_position
 3145            {
 3146                let start_offset = selection_start.to_offset(buffer);
 3147                let position_matches = start_offset == completion_position.to_offset(buffer);
 3148                let continue_showing = if position_matches {
 3149                    if self.snippet_stack.is_empty() {
 3150                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3151                            == Some(CharKind::Word)
 3152                    } else {
 3153                        // Snippet choices can be shown even when the cursor is in whitespace.
 3154                        // Dismissing the menu with actions like backspace is handled by
 3155                        // invalidation regions.
 3156                        true
 3157                    }
 3158                } else {
 3159                    false
 3160                };
 3161
 3162                if continue_showing {
 3163                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3164                } else {
 3165                    self.hide_context_menu(window, cx);
 3166                }
 3167            }
 3168
 3169            hide_hover(self, cx);
 3170
 3171            if old_cursor_position.to_display_point(&display_map).row()
 3172                != new_cursor_position.to_display_point(&display_map).row()
 3173            {
 3174                self.available_code_actions.take();
 3175            }
 3176            self.refresh_code_actions(window, cx);
 3177            self.refresh_document_highlights(cx);
 3178            refresh_linked_ranges(self, window, cx);
 3179
 3180            self.refresh_selected_text_highlights(false, window, cx);
 3181            refresh_matching_bracket_highlights(self, cx);
 3182            self.update_visible_edit_prediction(window, cx);
 3183            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3184            self.inline_blame_popover.take();
 3185            if self.git_blame_inline_enabled {
 3186                self.start_inline_blame_timer(window, cx);
 3187            }
 3188        }
 3189
 3190        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3191        cx.emit(EditorEvent::SelectionsChanged { local });
 3192
 3193        let selections = &self.selections.disjoint_anchors_arc();
 3194        if selections.len() == 1 {
 3195            cx.emit(SearchEvent::ActiveMatchChanged)
 3196        }
 3197        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3198            let inmemory_selections = selections
 3199                .iter()
 3200                .map(|s| {
 3201                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3202                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3203                })
 3204                .collect();
 3205            self.update_restoration_data(cx, |data| {
 3206                data.selections = inmemory_selections;
 3207            });
 3208
 3209            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3210                && let Some(workspace_id) =
 3211                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3212            {
 3213                let snapshot = self.buffer().read(cx).snapshot(cx);
 3214                let selections = selections.clone();
 3215                let background_executor = cx.background_executor().clone();
 3216                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3217                self.serialize_selections = cx.background_spawn(async move {
 3218                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3219                    let db_selections = selections
 3220                        .iter()
 3221                        .map(|selection| {
 3222                            (
 3223                                selection.start.to_offset(&snapshot),
 3224                                selection.end.to_offset(&snapshot),
 3225                            )
 3226                        })
 3227                        .collect();
 3228
 3229                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3230                        .await
 3231                        .with_context(|| {
 3232                            format!(
 3233                                "persisting editor selections for editor {editor_id}, \
 3234                                workspace {workspace_id:?}"
 3235                            )
 3236                        })
 3237                        .log_err();
 3238                });
 3239            }
 3240        }
 3241
 3242        cx.notify();
 3243    }
 3244
 3245    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3246        use text::ToOffset as _;
 3247        use text::ToPoint as _;
 3248
 3249        if self.mode.is_minimap()
 3250            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3251        {
 3252            return;
 3253        }
 3254
 3255        if !self.buffer().read(cx).is_singleton() {
 3256            return;
 3257        }
 3258
 3259        let display_snapshot = self
 3260            .display_map
 3261            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3262        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3263            return;
 3264        };
 3265        let inmemory_folds = display_snapshot
 3266            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3267            .map(|fold| {
 3268                fold.range.start.text_anchor.to_point(&snapshot)
 3269                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3270            })
 3271            .collect();
 3272        self.update_restoration_data(cx, |data| {
 3273            data.folds = inmemory_folds;
 3274        });
 3275
 3276        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3277            return;
 3278        };
 3279        let background_executor = cx.background_executor().clone();
 3280        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3281        let db_folds = display_snapshot
 3282            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3283            .map(|fold| {
 3284                (
 3285                    fold.range.start.text_anchor.to_offset(&snapshot),
 3286                    fold.range.end.text_anchor.to_offset(&snapshot),
 3287                )
 3288            })
 3289            .collect();
 3290        self.serialize_folds = cx.background_spawn(async move {
 3291            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3292            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3293                .await
 3294                .with_context(|| {
 3295                    format!(
 3296                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3297                    )
 3298                })
 3299                .log_err();
 3300        });
 3301    }
 3302
 3303    pub fn sync_selections(
 3304        &mut self,
 3305        other: Entity<Editor>,
 3306        cx: &mut Context<Self>,
 3307    ) -> gpui::Subscription {
 3308        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3309        if !other_selections.is_empty() {
 3310            self.selections.change_with(cx, |selections| {
 3311                selections.select_anchors(other_selections);
 3312            });
 3313        }
 3314
 3315        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3316            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3317                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3318                if other_selections.is_empty() {
 3319                    return;
 3320                }
 3321                this.selections.change_with(cx, |selections| {
 3322                    selections.select_anchors(other_selections);
 3323                });
 3324            }
 3325        });
 3326
 3327        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3328            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3329                let these_selections = this.selections.disjoint_anchors().to_vec();
 3330                if these_selections.is_empty() {
 3331                    return;
 3332                }
 3333                other.update(cx, |other_editor, cx| {
 3334                    other_editor.selections.change_with(cx, |selections| {
 3335                        selections.select_anchors(these_selections);
 3336                    })
 3337                });
 3338            }
 3339        });
 3340
 3341        Subscription::join(other_subscription, this_subscription)
 3342    }
 3343
 3344    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3345    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3346    /// effects of selection change occur at the end of the transaction.
 3347    pub fn change_selections<R>(
 3348        &mut self,
 3349        effects: SelectionEffects,
 3350        window: &mut Window,
 3351        cx: &mut Context<Self>,
 3352        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3353    ) -> R {
 3354        if let Some(state) = &mut self.deferred_selection_effects_state {
 3355            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3356            state.effects.completions = effects.completions;
 3357            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3358            let (changed, result) = self.selections.change_with(cx, change);
 3359            state.changed |= changed;
 3360            return result;
 3361        }
 3362        let mut state = DeferredSelectionEffectsState {
 3363            changed: false,
 3364            effects,
 3365            old_cursor_position: self.selections.newest_anchor().head(),
 3366            history_entry: SelectionHistoryEntry {
 3367                selections: self.selections.disjoint_anchors_arc(),
 3368                select_next_state: self.select_next_state.clone(),
 3369                select_prev_state: self.select_prev_state.clone(),
 3370                add_selections_state: self.add_selections_state.clone(),
 3371            },
 3372        };
 3373        let (changed, result) = self.selections.change_with(cx, change);
 3374        state.changed = state.changed || changed;
 3375        if self.defer_selection_effects {
 3376            self.deferred_selection_effects_state = Some(state);
 3377        } else {
 3378            self.apply_selection_effects(state, window, cx);
 3379        }
 3380        result
 3381    }
 3382
 3383    /// Defers the effects of selection change, so that the effects of multiple calls to
 3384    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3385    /// to selection history and the state of popovers based on selection position aren't
 3386    /// erroneously updated.
 3387    pub fn with_selection_effects_deferred<R>(
 3388        &mut self,
 3389        window: &mut Window,
 3390        cx: &mut Context<Self>,
 3391        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3392    ) -> R {
 3393        let already_deferred = self.defer_selection_effects;
 3394        self.defer_selection_effects = true;
 3395        let result = update(self, window, cx);
 3396        if !already_deferred {
 3397            self.defer_selection_effects = false;
 3398            if let Some(state) = self.deferred_selection_effects_state.take() {
 3399                self.apply_selection_effects(state, window, cx);
 3400            }
 3401        }
 3402        result
 3403    }
 3404
 3405    fn apply_selection_effects(
 3406        &mut self,
 3407        state: DeferredSelectionEffectsState,
 3408        window: &mut Window,
 3409        cx: &mut Context<Self>,
 3410    ) {
 3411        if state.changed {
 3412            self.selection_history.push(state.history_entry);
 3413
 3414            if let Some(autoscroll) = state.effects.scroll {
 3415                self.request_autoscroll(autoscroll, cx);
 3416            }
 3417
 3418            let old_cursor_position = &state.old_cursor_position;
 3419
 3420            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3421
 3422            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3423                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3424            }
 3425        }
 3426    }
 3427
 3428    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3429    where
 3430        I: IntoIterator<Item = (Range<S>, T)>,
 3431        S: ToOffset,
 3432        T: Into<Arc<str>>,
 3433    {
 3434        if self.read_only(cx) {
 3435            return;
 3436        }
 3437
 3438        self.buffer
 3439            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3440    }
 3441
 3442    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3443    where
 3444        I: IntoIterator<Item = (Range<S>, T)>,
 3445        S: ToOffset,
 3446        T: Into<Arc<str>>,
 3447    {
 3448        if self.read_only(cx) {
 3449            return;
 3450        }
 3451
 3452        self.buffer.update(cx, |buffer, cx| {
 3453            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3454        });
 3455    }
 3456
 3457    pub fn edit_with_block_indent<I, S, T>(
 3458        &mut self,
 3459        edits: I,
 3460        original_indent_columns: Vec<Option<u32>>,
 3461        cx: &mut Context<Self>,
 3462    ) where
 3463        I: IntoIterator<Item = (Range<S>, T)>,
 3464        S: ToOffset,
 3465        T: Into<Arc<str>>,
 3466    {
 3467        if self.read_only(cx) {
 3468            return;
 3469        }
 3470
 3471        self.buffer.update(cx, |buffer, cx| {
 3472            buffer.edit(
 3473                edits,
 3474                Some(AutoindentMode::Block {
 3475                    original_indent_columns,
 3476                }),
 3477                cx,
 3478            )
 3479        });
 3480    }
 3481
 3482    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3483        self.hide_context_menu(window, cx);
 3484
 3485        match phase {
 3486            SelectPhase::Begin {
 3487                position,
 3488                add,
 3489                click_count,
 3490            } => self.begin_selection(position, add, click_count, window, cx),
 3491            SelectPhase::BeginColumnar {
 3492                position,
 3493                goal_column,
 3494                reset,
 3495                mode,
 3496            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3497            SelectPhase::Extend {
 3498                position,
 3499                click_count,
 3500            } => self.extend_selection(position, click_count, window, cx),
 3501            SelectPhase::Update {
 3502                position,
 3503                goal_column,
 3504                scroll_delta,
 3505            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3506            SelectPhase::End => self.end_selection(window, cx),
 3507        }
 3508    }
 3509
 3510    fn extend_selection(
 3511        &mut self,
 3512        position: DisplayPoint,
 3513        click_count: usize,
 3514        window: &mut Window,
 3515        cx: &mut Context<Self>,
 3516    ) {
 3517        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3518        let tail = self.selections.newest::<usize>(&display_map).tail();
 3519        let click_count = click_count.max(match self.selections.select_mode() {
 3520            SelectMode::Character => 1,
 3521            SelectMode::Word(_) => 2,
 3522            SelectMode::Line(_) => 3,
 3523            SelectMode::All => 4,
 3524        });
 3525        self.begin_selection(position, false, click_count, window, cx);
 3526
 3527        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3528
 3529        let current_selection = match self.selections.select_mode() {
 3530            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3531            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3532        };
 3533
 3534        let mut pending_selection = self
 3535            .selections
 3536            .pending_anchor()
 3537            .cloned()
 3538            .expect("extend_selection not called with pending selection");
 3539
 3540        if pending_selection
 3541            .start
 3542            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3543            == Ordering::Greater
 3544        {
 3545            pending_selection.start = current_selection.start;
 3546        }
 3547        if pending_selection
 3548            .end
 3549            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3550            == Ordering::Less
 3551        {
 3552            pending_selection.end = current_selection.end;
 3553            pending_selection.reversed = true;
 3554        }
 3555
 3556        let mut pending_mode = self.selections.pending_mode().unwrap();
 3557        match &mut pending_mode {
 3558            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3559            _ => {}
 3560        }
 3561
 3562        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3563            SelectionEffects::scroll(Autoscroll::fit())
 3564        } else {
 3565            SelectionEffects::no_scroll()
 3566        };
 3567
 3568        self.change_selections(effects, window, cx, |s| {
 3569            s.set_pending(pending_selection.clone(), pending_mode);
 3570            s.set_is_extending(true);
 3571        });
 3572    }
 3573
 3574    fn begin_selection(
 3575        &mut self,
 3576        position: DisplayPoint,
 3577        add: bool,
 3578        click_count: usize,
 3579        window: &mut Window,
 3580        cx: &mut Context<Self>,
 3581    ) {
 3582        if !self.focus_handle.is_focused(window) {
 3583            self.last_focused_descendant = None;
 3584            window.focus(&self.focus_handle);
 3585        }
 3586
 3587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3588        let buffer = display_map.buffer_snapshot();
 3589        let position = display_map.clip_point(position, Bias::Left);
 3590
 3591        let start;
 3592        let end;
 3593        let mode;
 3594        let mut auto_scroll;
 3595        match click_count {
 3596            1 => {
 3597                start = buffer.anchor_before(position.to_point(&display_map));
 3598                end = start;
 3599                mode = SelectMode::Character;
 3600                auto_scroll = true;
 3601            }
 3602            2 => {
 3603                let position = display_map
 3604                    .clip_point(position, Bias::Left)
 3605                    .to_offset(&display_map, Bias::Left);
 3606                let (range, _) = buffer.surrounding_word(position, None);
 3607                start = buffer.anchor_before(range.start);
 3608                end = buffer.anchor_before(range.end);
 3609                mode = SelectMode::Word(start..end);
 3610                auto_scroll = true;
 3611            }
 3612            3 => {
 3613                let position = display_map
 3614                    .clip_point(position, Bias::Left)
 3615                    .to_point(&display_map);
 3616                let line_start = display_map.prev_line_boundary(position).0;
 3617                let next_line_start = buffer.clip_point(
 3618                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3619                    Bias::Left,
 3620                );
 3621                start = buffer.anchor_before(line_start);
 3622                end = buffer.anchor_before(next_line_start);
 3623                mode = SelectMode::Line(start..end);
 3624                auto_scroll = true;
 3625            }
 3626            _ => {
 3627                start = buffer.anchor_before(0);
 3628                end = buffer.anchor_before(buffer.len());
 3629                mode = SelectMode::All;
 3630                auto_scroll = false;
 3631            }
 3632        }
 3633        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3634
 3635        let point_to_delete: Option<usize> = {
 3636            let selected_points: Vec<Selection<Point>> =
 3637                self.selections.disjoint_in_range(start..end, &display_map);
 3638
 3639            if !add || click_count > 1 {
 3640                None
 3641            } else if !selected_points.is_empty() {
 3642                Some(selected_points[0].id)
 3643            } else {
 3644                let clicked_point_already_selected =
 3645                    self.selections.disjoint_anchors().iter().find(|selection| {
 3646                        selection.start.to_point(buffer) == start.to_point(buffer)
 3647                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3648                    });
 3649
 3650                clicked_point_already_selected.map(|selection| selection.id)
 3651            }
 3652        };
 3653
 3654        let selections_count = self.selections.count();
 3655        let effects = if auto_scroll {
 3656            SelectionEffects::default()
 3657        } else {
 3658            SelectionEffects::no_scroll()
 3659        };
 3660
 3661        self.change_selections(effects, window, cx, |s| {
 3662            if let Some(point_to_delete) = point_to_delete {
 3663                s.delete(point_to_delete);
 3664
 3665                if selections_count == 1 {
 3666                    s.set_pending_anchor_range(start..end, mode);
 3667                }
 3668            } else {
 3669                if !add {
 3670                    s.clear_disjoint();
 3671                }
 3672
 3673                s.set_pending_anchor_range(start..end, mode);
 3674            }
 3675        });
 3676    }
 3677
 3678    fn begin_columnar_selection(
 3679        &mut self,
 3680        position: DisplayPoint,
 3681        goal_column: u32,
 3682        reset: bool,
 3683        mode: ColumnarMode,
 3684        window: &mut Window,
 3685        cx: &mut Context<Self>,
 3686    ) {
 3687        if !self.focus_handle.is_focused(window) {
 3688            self.last_focused_descendant = None;
 3689            window.focus(&self.focus_handle);
 3690        }
 3691
 3692        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3693
 3694        if reset {
 3695            let pointer_position = display_map
 3696                .buffer_snapshot()
 3697                .anchor_before(position.to_point(&display_map));
 3698
 3699            self.change_selections(
 3700                SelectionEffects::scroll(Autoscroll::newest()),
 3701                window,
 3702                cx,
 3703                |s| {
 3704                    s.clear_disjoint();
 3705                    s.set_pending_anchor_range(
 3706                        pointer_position..pointer_position,
 3707                        SelectMode::Character,
 3708                    );
 3709                },
 3710            );
 3711        };
 3712
 3713        let tail = self.selections.newest::<Point>(&display_map).tail();
 3714        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3715        self.columnar_selection_state = match mode {
 3716            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3717                selection_tail: selection_anchor,
 3718                display_point: if reset {
 3719                    if position.column() != goal_column {
 3720                        Some(DisplayPoint::new(position.row(), goal_column))
 3721                    } else {
 3722                        None
 3723                    }
 3724                } else {
 3725                    None
 3726                },
 3727            }),
 3728            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3729                selection_tail: selection_anchor,
 3730            }),
 3731        };
 3732
 3733        if !reset {
 3734            self.select_columns(position, goal_column, &display_map, window, cx);
 3735        }
 3736    }
 3737
 3738    fn update_selection(
 3739        &mut self,
 3740        position: DisplayPoint,
 3741        goal_column: u32,
 3742        scroll_delta: gpui::Point<f32>,
 3743        window: &mut Window,
 3744        cx: &mut Context<Self>,
 3745    ) {
 3746        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3747
 3748        if self.columnar_selection_state.is_some() {
 3749            self.select_columns(position, goal_column, &display_map, window, cx);
 3750        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3751            let buffer = display_map.buffer_snapshot();
 3752            let head;
 3753            let tail;
 3754            let mode = self.selections.pending_mode().unwrap();
 3755            match &mode {
 3756                SelectMode::Character => {
 3757                    head = position.to_point(&display_map);
 3758                    tail = pending.tail().to_point(buffer);
 3759                }
 3760                SelectMode::Word(original_range) => {
 3761                    let offset = display_map
 3762                        .clip_point(position, Bias::Left)
 3763                        .to_offset(&display_map, Bias::Left);
 3764                    let original_range = original_range.to_offset(buffer);
 3765
 3766                    let head_offset = if buffer.is_inside_word(offset, None)
 3767                        || original_range.contains(&offset)
 3768                    {
 3769                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3770                        if word_range.start < original_range.start {
 3771                            word_range.start
 3772                        } else {
 3773                            word_range.end
 3774                        }
 3775                    } else {
 3776                        offset
 3777                    };
 3778
 3779                    head = head_offset.to_point(buffer);
 3780                    if head_offset <= original_range.start {
 3781                        tail = original_range.end.to_point(buffer);
 3782                    } else {
 3783                        tail = original_range.start.to_point(buffer);
 3784                    }
 3785                }
 3786                SelectMode::Line(original_range) => {
 3787                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3788
 3789                    let position = display_map
 3790                        .clip_point(position, Bias::Left)
 3791                        .to_point(&display_map);
 3792                    let line_start = display_map.prev_line_boundary(position).0;
 3793                    let next_line_start = buffer.clip_point(
 3794                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3795                        Bias::Left,
 3796                    );
 3797
 3798                    if line_start < original_range.start {
 3799                        head = line_start
 3800                    } else {
 3801                        head = next_line_start
 3802                    }
 3803
 3804                    if head <= original_range.start {
 3805                        tail = original_range.end;
 3806                    } else {
 3807                        tail = original_range.start;
 3808                    }
 3809                }
 3810                SelectMode::All => {
 3811                    return;
 3812                }
 3813            };
 3814
 3815            if head < tail {
 3816                pending.start = buffer.anchor_before(head);
 3817                pending.end = buffer.anchor_before(tail);
 3818                pending.reversed = true;
 3819            } else {
 3820                pending.start = buffer.anchor_before(tail);
 3821                pending.end = buffer.anchor_before(head);
 3822                pending.reversed = false;
 3823            }
 3824
 3825            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3826                s.set_pending(pending.clone(), mode);
 3827            });
 3828        } else {
 3829            log::error!("update_selection dispatched with no pending selection");
 3830            return;
 3831        }
 3832
 3833        self.apply_scroll_delta(scroll_delta, window, cx);
 3834        cx.notify();
 3835    }
 3836
 3837    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3838        self.columnar_selection_state.take();
 3839        if let Some(pending_mode) = self.selections.pending_mode() {
 3840            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3841            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3842                s.select(selections);
 3843                s.clear_pending();
 3844                if s.is_extending() {
 3845                    s.set_is_extending(false);
 3846                } else {
 3847                    s.set_select_mode(pending_mode);
 3848                }
 3849            });
 3850        }
 3851    }
 3852
 3853    fn select_columns(
 3854        &mut self,
 3855        head: DisplayPoint,
 3856        goal_column: u32,
 3857        display_map: &DisplaySnapshot,
 3858        window: &mut Window,
 3859        cx: &mut Context<Self>,
 3860    ) {
 3861        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3862            return;
 3863        };
 3864
 3865        let tail = match columnar_state {
 3866            ColumnarSelectionState::FromMouse {
 3867                selection_tail,
 3868                display_point,
 3869            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3870            ColumnarSelectionState::FromSelection { selection_tail } => {
 3871                selection_tail.to_display_point(display_map)
 3872            }
 3873        };
 3874
 3875        let start_row = cmp::min(tail.row(), head.row());
 3876        let end_row = cmp::max(tail.row(), head.row());
 3877        let start_column = cmp::min(tail.column(), goal_column);
 3878        let end_column = cmp::max(tail.column(), goal_column);
 3879        let reversed = start_column < tail.column();
 3880
 3881        let selection_ranges = (start_row.0..=end_row.0)
 3882            .map(DisplayRow)
 3883            .filter_map(|row| {
 3884                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3885                    || start_column <= display_map.line_len(row))
 3886                    && !display_map.is_block_line(row)
 3887                {
 3888                    let start = display_map
 3889                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3890                        .to_point(display_map);
 3891                    let end = display_map
 3892                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3893                        .to_point(display_map);
 3894                    if reversed {
 3895                        Some(end..start)
 3896                    } else {
 3897                        Some(start..end)
 3898                    }
 3899                } else {
 3900                    None
 3901                }
 3902            })
 3903            .collect::<Vec<_>>();
 3904        if selection_ranges.is_empty() {
 3905            return;
 3906        }
 3907
 3908        let ranges = match columnar_state {
 3909            ColumnarSelectionState::FromMouse { .. } => {
 3910                let mut non_empty_ranges = selection_ranges
 3911                    .iter()
 3912                    .filter(|selection_range| selection_range.start != selection_range.end)
 3913                    .peekable();
 3914                if non_empty_ranges.peek().is_some() {
 3915                    non_empty_ranges.cloned().collect()
 3916                } else {
 3917                    selection_ranges
 3918                }
 3919            }
 3920            _ => selection_ranges,
 3921        };
 3922
 3923        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3924            s.select_ranges(ranges);
 3925        });
 3926        cx.notify();
 3927    }
 3928
 3929    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3930        self.selections
 3931            .all_adjusted(snapshot)
 3932            .iter()
 3933            .any(|selection| !selection.is_empty())
 3934    }
 3935
 3936    pub fn has_pending_nonempty_selection(&self) -> bool {
 3937        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3938            Some(Selection { start, end, .. }) => start != end,
 3939            None => false,
 3940        };
 3941
 3942        pending_nonempty_selection
 3943            || (self.columnar_selection_state.is_some()
 3944                && self.selections.disjoint_anchors().len() > 1)
 3945    }
 3946
 3947    pub fn has_pending_selection(&self) -> bool {
 3948        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3949    }
 3950
 3951    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3952        self.selection_mark_mode = false;
 3953        self.selection_drag_state = SelectionDragState::None;
 3954
 3955        if self.clear_expanded_diff_hunks(cx) {
 3956            cx.notify();
 3957            return;
 3958        }
 3959        if self.dismiss_menus_and_popups(true, window, cx) {
 3960            return;
 3961        }
 3962
 3963        if self.mode.is_full()
 3964            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3965        {
 3966            return;
 3967        }
 3968
 3969        cx.propagate();
 3970    }
 3971
 3972    pub fn dismiss_menus_and_popups(
 3973        &mut self,
 3974        is_user_requested: bool,
 3975        window: &mut Window,
 3976        cx: &mut Context<Self>,
 3977    ) -> bool {
 3978        if self.take_rename(false, window, cx).is_some() {
 3979            return true;
 3980        }
 3981
 3982        if hide_hover(self, cx) {
 3983            return true;
 3984        }
 3985
 3986        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3987            return true;
 3988        }
 3989
 3990        if self.hide_context_menu(window, cx).is_some() {
 3991            return true;
 3992        }
 3993
 3994        if self.mouse_context_menu.take().is_some() {
 3995            return true;
 3996        }
 3997
 3998        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3999            return true;
 4000        }
 4001
 4002        if self.snippet_stack.pop().is_some() {
 4003            return true;
 4004        }
 4005
 4006        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4007            self.dismiss_diagnostics(cx);
 4008            return true;
 4009        }
 4010
 4011        false
 4012    }
 4013
 4014    fn linked_editing_ranges_for(
 4015        &self,
 4016        selection: Range<text::Anchor>,
 4017        cx: &App,
 4018    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4019        if self.linked_edit_ranges.is_empty() {
 4020            return None;
 4021        }
 4022        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4023            selection.end.buffer_id.and_then(|end_buffer_id| {
 4024                if selection.start.buffer_id != Some(end_buffer_id) {
 4025                    return None;
 4026                }
 4027                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4028                let snapshot = buffer.read(cx).snapshot();
 4029                self.linked_edit_ranges
 4030                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4031                    .map(|ranges| (ranges, snapshot, buffer))
 4032            })?;
 4033        use text::ToOffset as TO;
 4034        // find offset from the start of current range to current cursor position
 4035        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4036
 4037        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4038        let start_difference = start_offset - start_byte_offset;
 4039        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4040        let end_difference = end_offset - start_byte_offset;
 4041        // Current range has associated linked ranges.
 4042        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4043        for range in linked_ranges.iter() {
 4044            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4045            let end_offset = start_offset + end_difference;
 4046            let start_offset = start_offset + start_difference;
 4047            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4048                continue;
 4049            }
 4050            if self.selections.disjoint_anchor_ranges().any(|s| {
 4051                if s.start.buffer_id != selection.start.buffer_id
 4052                    || s.end.buffer_id != selection.end.buffer_id
 4053                {
 4054                    return false;
 4055                }
 4056                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4057                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4058            }) {
 4059                continue;
 4060            }
 4061            let start = buffer_snapshot.anchor_after(start_offset);
 4062            let end = buffer_snapshot.anchor_after(end_offset);
 4063            linked_edits
 4064                .entry(buffer.clone())
 4065                .or_default()
 4066                .push(start..end);
 4067        }
 4068        Some(linked_edits)
 4069    }
 4070
 4071    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4072        let text: Arc<str> = text.into();
 4073
 4074        if self.read_only(cx) {
 4075            return;
 4076        }
 4077
 4078        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4079
 4080        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4081        let mut bracket_inserted = false;
 4082        let mut edits = Vec::new();
 4083        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4084        let mut new_selections = Vec::with_capacity(selections.len());
 4085        let mut new_autoclose_regions = Vec::new();
 4086        let snapshot = self.buffer.read(cx).read(cx);
 4087        let mut clear_linked_edit_ranges = false;
 4088
 4089        for (selection, autoclose_region) in
 4090            self.selections_with_autoclose_regions(selections, &snapshot)
 4091        {
 4092            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4093                // Determine if the inserted text matches the opening or closing
 4094                // bracket of any of this language's bracket pairs.
 4095                let mut bracket_pair = None;
 4096                let mut is_bracket_pair_start = false;
 4097                let mut is_bracket_pair_end = false;
 4098                if !text.is_empty() {
 4099                    let mut bracket_pair_matching_end = None;
 4100                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4101                    //  and they are removing the character that triggered IME popup.
 4102                    for (pair, enabled) in scope.brackets() {
 4103                        if !pair.close && !pair.surround {
 4104                            continue;
 4105                        }
 4106
 4107                        if enabled && pair.start.ends_with(text.as_ref()) {
 4108                            let prefix_len = pair.start.len() - text.len();
 4109                            let preceding_text_matches_prefix = prefix_len == 0
 4110                                || (selection.start.column >= (prefix_len as u32)
 4111                                    && snapshot.contains_str_at(
 4112                                        Point::new(
 4113                                            selection.start.row,
 4114                                            selection.start.column - (prefix_len as u32),
 4115                                        ),
 4116                                        &pair.start[..prefix_len],
 4117                                    ));
 4118                            if preceding_text_matches_prefix {
 4119                                bracket_pair = Some(pair.clone());
 4120                                is_bracket_pair_start = true;
 4121                                break;
 4122                            }
 4123                        }
 4124                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4125                        {
 4126                            // take first bracket pair matching end, but don't break in case a later bracket
 4127                            // pair matches start
 4128                            bracket_pair_matching_end = Some(pair.clone());
 4129                        }
 4130                    }
 4131                    if let Some(end) = bracket_pair_matching_end
 4132                        && bracket_pair.is_none()
 4133                    {
 4134                        bracket_pair = Some(end);
 4135                        is_bracket_pair_end = true;
 4136                    }
 4137                }
 4138
 4139                if let Some(bracket_pair) = bracket_pair {
 4140                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4141                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4142                    let auto_surround =
 4143                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4144                    if selection.is_empty() {
 4145                        if is_bracket_pair_start {
 4146                            // If the inserted text is a suffix of an opening bracket and the
 4147                            // selection is preceded by the rest of the opening bracket, then
 4148                            // insert the closing bracket.
 4149                            let following_text_allows_autoclose = snapshot
 4150                                .chars_at(selection.start)
 4151                                .next()
 4152                                .is_none_or(|c| scope.should_autoclose_before(c));
 4153
 4154                            let preceding_text_allows_autoclose = selection.start.column == 0
 4155                                || snapshot
 4156                                    .reversed_chars_at(selection.start)
 4157                                    .next()
 4158                                    .is_none_or(|c| {
 4159                                        bracket_pair.start != bracket_pair.end
 4160                                            || !snapshot
 4161                                                .char_classifier_at(selection.start)
 4162                                                .is_word(c)
 4163                                    });
 4164
 4165                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4166                                && bracket_pair.start.len() == 1
 4167                            {
 4168                                let target = bracket_pair.start.chars().next().unwrap();
 4169                                let current_line_count = snapshot
 4170                                    .reversed_chars_at(selection.start)
 4171                                    .take_while(|&c| c != '\n')
 4172                                    .filter(|&c| c == target)
 4173                                    .count();
 4174                                current_line_count % 2 == 1
 4175                            } else {
 4176                                false
 4177                            };
 4178
 4179                            if autoclose
 4180                                && bracket_pair.close
 4181                                && following_text_allows_autoclose
 4182                                && preceding_text_allows_autoclose
 4183                                && !is_closing_quote
 4184                            {
 4185                                let anchor = snapshot.anchor_before(selection.end);
 4186                                new_selections.push((selection.map(|_| anchor), text.len()));
 4187                                new_autoclose_regions.push((
 4188                                    anchor,
 4189                                    text.len(),
 4190                                    selection.id,
 4191                                    bracket_pair.clone(),
 4192                                ));
 4193                                edits.push((
 4194                                    selection.range(),
 4195                                    format!("{}{}", text, bracket_pair.end).into(),
 4196                                ));
 4197                                bracket_inserted = true;
 4198                                continue;
 4199                            }
 4200                        }
 4201
 4202                        if let Some(region) = autoclose_region {
 4203                            // If the selection is followed by an auto-inserted closing bracket,
 4204                            // then don't insert that closing bracket again; just move the selection
 4205                            // past the closing bracket.
 4206                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4207                                && text.as_ref() == region.pair.end.as_str()
 4208                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4209                            if should_skip {
 4210                                let anchor = snapshot.anchor_after(selection.end);
 4211                                new_selections
 4212                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4213                                continue;
 4214                            }
 4215                        }
 4216
 4217                        let always_treat_brackets_as_autoclosed = snapshot
 4218                            .language_settings_at(selection.start, cx)
 4219                            .always_treat_brackets_as_autoclosed;
 4220                        if always_treat_brackets_as_autoclosed
 4221                            && is_bracket_pair_end
 4222                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4223                        {
 4224                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4225                            // and the inserted text is a closing bracket and the selection is followed
 4226                            // by the closing bracket then move the selection past the closing bracket.
 4227                            let anchor = snapshot.anchor_after(selection.end);
 4228                            new_selections.push((selection.map(|_| anchor), text.len()));
 4229                            continue;
 4230                        }
 4231                    }
 4232                    // If an opening bracket is 1 character long and is typed while
 4233                    // text is selected, then surround that text with the bracket pair.
 4234                    else if auto_surround
 4235                        && bracket_pair.surround
 4236                        && is_bracket_pair_start
 4237                        && bracket_pair.start.chars().count() == 1
 4238                    {
 4239                        edits.push((selection.start..selection.start, text.clone()));
 4240                        edits.push((
 4241                            selection.end..selection.end,
 4242                            bracket_pair.end.as_str().into(),
 4243                        ));
 4244                        bracket_inserted = true;
 4245                        new_selections.push((
 4246                            Selection {
 4247                                id: selection.id,
 4248                                start: snapshot.anchor_after(selection.start),
 4249                                end: snapshot.anchor_before(selection.end),
 4250                                reversed: selection.reversed,
 4251                                goal: selection.goal,
 4252                            },
 4253                            0,
 4254                        ));
 4255                        continue;
 4256                    }
 4257                }
 4258            }
 4259
 4260            if self.auto_replace_emoji_shortcode
 4261                && selection.is_empty()
 4262                && text.as_ref().ends_with(':')
 4263                && let Some(possible_emoji_short_code) =
 4264                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4265                && !possible_emoji_short_code.is_empty()
 4266                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4267            {
 4268                let emoji_shortcode_start = Point::new(
 4269                    selection.start.row,
 4270                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4271                );
 4272
 4273                // Remove shortcode from buffer
 4274                edits.push((
 4275                    emoji_shortcode_start..selection.start,
 4276                    "".to_string().into(),
 4277                ));
 4278                new_selections.push((
 4279                    Selection {
 4280                        id: selection.id,
 4281                        start: snapshot.anchor_after(emoji_shortcode_start),
 4282                        end: snapshot.anchor_before(selection.start),
 4283                        reversed: selection.reversed,
 4284                        goal: selection.goal,
 4285                    },
 4286                    0,
 4287                ));
 4288
 4289                // Insert emoji
 4290                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4291                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4292                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4293
 4294                continue;
 4295            }
 4296
 4297            // If not handling any auto-close operation, then just replace the selected
 4298            // text with the given input and move the selection to the end of the
 4299            // newly inserted text.
 4300            let anchor = snapshot.anchor_after(selection.end);
 4301            if !self.linked_edit_ranges.is_empty() {
 4302                let start_anchor = snapshot.anchor_before(selection.start);
 4303
 4304                let is_word_char = text.chars().next().is_none_or(|char| {
 4305                    let classifier = snapshot
 4306                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4307                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4308                    classifier.is_word(char)
 4309                });
 4310
 4311                if is_word_char {
 4312                    if let Some(ranges) = self
 4313                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4314                    {
 4315                        for (buffer, edits) in ranges {
 4316                            linked_edits
 4317                                .entry(buffer.clone())
 4318                                .or_default()
 4319                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4320                        }
 4321                    }
 4322                } else {
 4323                    clear_linked_edit_ranges = true;
 4324                }
 4325            }
 4326
 4327            new_selections.push((selection.map(|_| anchor), 0));
 4328            edits.push((selection.start..selection.end, text.clone()));
 4329        }
 4330
 4331        drop(snapshot);
 4332
 4333        self.transact(window, cx, |this, window, cx| {
 4334            if clear_linked_edit_ranges {
 4335                this.linked_edit_ranges.clear();
 4336            }
 4337            let initial_buffer_versions =
 4338                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4339
 4340            this.buffer.update(cx, |buffer, cx| {
 4341                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4342            });
 4343            for (buffer, edits) in linked_edits {
 4344                buffer.update(cx, |buffer, cx| {
 4345                    let snapshot = buffer.snapshot();
 4346                    let edits = edits
 4347                        .into_iter()
 4348                        .map(|(range, text)| {
 4349                            use text::ToPoint as TP;
 4350                            let end_point = TP::to_point(&range.end, &snapshot);
 4351                            let start_point = TP::to_point(&range.start, &snapshot);
 4352                            (start_point..end_point, text)
 4353                        })
 4354                        .sorted_by_key(|(range, _)| range.start);
 4355                    buffer.edit(edits, None, cx);
 4356                })
 4357            }
 4358            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4359            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4360            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4361            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4362                .zip(new_selection_deltas)
 4363                .map(|(selection, delta)| Selection {
 4364                    id: selection.id,
 4365                    start: selection.start + delta,
 4366                    end: selection.end + delta,
 4367                    reversed: selection.reversed,
 4368                    goal: SelectionGoal::None,
 4369                })
 4370                .collect::<Vec<_>>();
 4371
 4372            let mut i = 0;
 4373            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4374                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4375                let start = map.buffer_snapshot().anchor_before(position);
 4376                let end = map.buffer_snapshot().anchor_after(position);
 4377                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4378                    match existing_state
 4379                        .range
 4380                        .start
 4381                        .cmp(&start, map.buffer_snapshot())
 4382                    {
 4383                        Ordering::Less => i += 1,
 4384                        Ordering::Greater => break,
 4385                        Ordering::Equal => {
 4386                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4387                                Ordering::Less => i += 1,
 4388                                Ordering::Equal => break,
 4389                                Ordering::Greater => break,
 4390                            }
 4391                        }
 4392                    }
 4393                }
 4394                this.autoclose_regions.insert(
 4395                    i,
 4396                    AutocloseRegion {
 4397                        selection_id,
 4398                        range: start..end,
 4399                        pair,
 4400                    },
 4401                );
 4402            }
 4403
 4404            let had_active_edit_prediction = this.has_active_edit_prediction();
 4405            this.change_selections(
 4406                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4407                window,
 4408                cx,
 4409                |s| s.select(new_selections),
 4410            );
 4411
 4412            if !bracket_inserted
 4413                && let Some(on_type_format_task) =
 4414                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4415            {
 4416                on_type_format_task.detach_and_log_err(cx);
 4417            }
 4418
 4419            let editor_settings = EditorSettings::get_global(cx);
 4420            if bracket_inserted
 4421                && (editor_settings.auto_signature_help
 4422                    || editor_settings.show_signature_help_after_edits)
 4423            {
 4424                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4425            }
 4426
 4427            let trigger_in_words =
 4428                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4429            if this.hard_wrap.is_some() {
 4430                let latest: Range<Point> = this.selections.newest(&map).range();
 4431                if latest.is_empty()
 4432                    && this
 4433                        .buffer()
 4434                        .read(cx)
 4435                        .snapshot(cx)
 4436                        .line_len(MultiBufferRow(latest.start.row))
 4437                        == latest.start.column
 4438                {
 4439                    this.rewrap_impl(
 4440                        RewrapOptions {
 4441                            override_language_settings: true,
 4442                            preserve_existing_whitespace: true,
 4443                        },
 4444                        cx,
 4445                    )
 4446                }
 4447            }
 4448            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4449            refresh_linked_ranges(this, window, cx);
 4450            this.refresh_edit_prediction(true, false, window, cx);
 4451            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4452        });
 4453    }
 4454
 4455    fn find_possible_emoji_shortcode_at_position(
 4456        snapshot: &MultiBufferSnapshot,
 4457        position: Point,
 4458    ) -> Option<String> {
 4459        let mut chars = Vec::new();
 4460        let mut found_colon = false;
 4461        for char in snapshot.reversed_chars_at(position).take(100) {
 4462            // Found a possible emoji shortcode in the middle of the buffer
 4463            if found_colon {
 4464                if char.is_whitespace() {
 4465                    chars.reverse();
 4466                    return Some(chars.iter().collect());
 4467                }
 4468                // If the previous character is not a whitespace, we are in the middle of a word
 4469                // and we only want to complete the shortcode if the word is made up of other emojis
 4470                let mut containing_word = String::new();
 4471                for ch in snapshot
 4472                    .reversed_chars_at(position)
 4473                    .skip(chars.len() + 1)
 4474                    .take(100)
 4475                {
 4476                    if ch.is_whitespace() {
 4477                        break;
 4478                    }
 4479                    containing_word.push(ch);
 4480                }
 4481                let containing_word = containing_word.chars().rev().collect::<String>();
 4482                if util::word_consists_of_emojis(containing_word.as_str()) {
 4483                    chars.reverse();
 4484                    return Some(chars.iter().collect());
 4485                }
 4486            }
 4487
 4488            if char.is_whitespace() || !char.is_ascii() {
 4489                return None;
 4490            }
 4491            if char == ':' {
 4492                found_colon = true;
 4493            } else {
 4494                chars.push(char);
 4495            }
 4496        }
 4497        // Found a possible emoji shortcode at the beginning of the buffer
 4498        chars.reverse();
 4499        Some(chars.iter().collect())
 4500    }
 4501
 4502    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4503        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4504        self.transact(window, cx, |this, window, cx| {
 4505            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4506                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4507                let multi_buffer = this.buffer.read(cx);
 4508                let buffer = multi_buffer.snapshot(cx);
 4509                selections
 4510                    .iter()
 4511                    .map(|selection| {
 4512                        let start_point = selection.start.to_point(&buffer);
 4513                        let mut existing_indent =
 4514                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4515                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4516                        let start = selection.start;
 4517                        let end = selection.end;
 4518                        let selection_is_empty = start == end;
 4519                        let language_scope = buffer.language_scope_at(start);
 4520                        let (
 4521                            comment_delimiter,
 4522                            doc_delimiter,
 4523                            insert_extra_newline,
 4524                            indent_on_newline,
 4525                            indent_on_extra_newline,
 4526                        ) = if let Some(language) = &language_scope {
 4527                            let mut insert_extra_newline =
 4528                                insert_extra_newline_brackets(&buffer, start..end, language)
 4529                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4530
 4531                            // Comment extension on newline is allowed only for cursor selections
 4532                            let comment_delimiter = maybe!({
 4533                                if !selection_is_empty {
 4534                                    return None;
 4535                                }
 4536
 4537                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4538                                    return None;
 4539                                }
 4540
 4541                                let delimiters = language.line_comment_prefixes();
 4542                                let max_len_of_delimiter =
 4543                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4544                                let (snapshot, range) =
 4545                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4546
 4547                                let num_of_whitespaces = snapshot
 4548                                    .chars_for_range(range.clone())
 4549                                    .take_while(|c| c.is_whitespace())
 4550                                    .count();
 4551                                let comment_candidate = snapshot
 4552                                    .chars_for_range(range.clone())
 4553                                    .skip(num_of_whitespaces)
 4554                                    .take(max_len_of_delimiter)
 4555                                    .collect::<String>();
 4556                                let (delimiter, trimmed_len) = delimiters
 4557                                    .iter()
 4558                                    .filter_map(|delimiter| {
 4559                                        let prefix = delimiter.trim_end();
 4560                                        if comment_candidate.starts_with(prefix) {
 4561                                            Some((delimiter, prefix.len()))
 4562                                        } else {
 4563                                            None
 4564                                        }
 4565                                    })
 4566                                    .max_by_key(|(_, len)| *len)?;
 4567
 4568                                if let Some(BlockCommentConfig {
 4569                                    start: block_start, ..
 4570                                }) = language.block_comment()
 4571                                {
 4572                                    let block_start_trimmed = block_start.trim_end();
 4573                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4574                                        let line_content = snapshot
 4575                                            .chars_for_range(range)
 4576                                            .skip(num_of_whitespaces)
 4577                                            .take(block_start_trimmed.len())
 4578                                            .collect::<String>();
 4579
 4580                                        if line_content.starts_with(block_start_trimmed) {
 4581                                            return None;
 4582                                        }
 4583                                    }
 4584                                }
 4585
 4586                                let cursor_is_placed_after_comment_marker =
 4587                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4588                                if cursor_is_placed_after_comment_marker {
 4589                                    Some(delimiter.clone())
 4590                                } else {
 4591                                    None
 4592                                }
 4593                            });
 4594
 4595                            let mut indent_on_newline = IndentSize::spaces(0);
 4596                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4597
 4598                            let doc_delimiter = maybe!({
 4599                                if !selection_is_empty {
 4600                                    return None;
 4601                                }
 4602
 4603                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4604                                    return None;
 4605                                }
 4606
 4607                                let BlockCommentConfig {
 4608                                    start: start_tag,
 4609                                    end: end_tag,
 4610                                    prefix: delimiter,
 4611                                    tab_size: len,
 4612                                } = language.documentation_comment()?;
 4613                                let is_within_block_comment = buffer
 4614                                    .language_scope_at(start_point)
 4615                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4616                                if !is_within_block_comment {
 4617                                    return None;
 4618                                }
 4619
 4620                                let (snapshot, range) =
 4621                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4622
 4623                                let num_of_whitespaces = snapshot
 4624                                    .chars_for_range(range.clone())
 4625                                    .take_while(|c| c.is_whitespace())
 4626                                    .count();
 4627
 4628                                // 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.
 4629                                let column = start_point.column;
 4630                                let cursor_is_after_start_tag = {
 4631                                    let start_tag_len = start_tag.len();
 4632                                    let start_tag_line = snapshot
 4633                                        .chars_for_range(range.clone())
 4634                                        .skip(num_of_whitespaces)
 4635                                        .take(start_tag_len)
 4636                                        .collect::<String>();
 4637                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4638                                        num_of_whitespaces + start_tag_len <= column as usize
 4639                                    } else {
 4640                                        false
 4641                                    }
 4642                                };
 4643
 4644                                let cursor_is_after_delimiter = {
 4645                                    let delimiter_trim = delimiter.trim_end();
 4646                                    let delimiter_line = snapshot
 4647                                        .chars_for_range(range.clone())
 4648                                        .skip(num_of_whitespaces)
 4649                                        .take(delimiter_trim.len())
 4650                                        .collect::<String>();
 4651                                    if delimiter_line.starts_with(delimiter_trim) {
 4652                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4653                                    } else {
 4654                                        false
 4655                                    }
 4656                                };
 4657
 4658                                let cursor_is_before_end_tag_if_exists = {
 4659                                    let mut char_position = 0u32;
 4660                                    let mut end_tag_offset = None;
 4661
 4662                                    'outer: for chunk in snapshot.text_for_range(range) {
 4663                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4664                                            let chars_before_match =
 4665                                                chunk[..byte_pos].chars().count() as u32;
 4666                                            end_tag_offset =
 4667                                                Some(char_position + chars_before_match);
 4668                                            break 'outer;
 4669                                        }
 4670                                        char_position += chunk.chars().count() as u32;
 4671                                    }
 4672
 4673                                    if let Some(end_tag_offset) = end_tag_offset {
 4674                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4675                                        if cursor_is_after_start_tag {
 4676                                            if cursor_is_before_end_tag {
 4677                                                insert_extra_newline = true;
 4678                                            }
 4679                                            let cursor_is_at_start_of_end_tag =
 4680                                                column == end_tag_offset;
 4681                                            if cursor_is_at_start_of_end_tag {
 4682                                                indent_on_extra_newline.len = *len;
 4683                                            }
 4684                                        }
 4685                                        cursor_is_before_end_tag
 4686                                    } else {
 4687                                        true
 4688                                    }
 4689                                };
 4690
 4691                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4692                                    && cursor_is_before_end_tag_if_exists
 4693                                {
 4694                                    if cursor_is_after_start_tag {
 4695                                        indent_on_newline.len = *len;
 4696                                    }
 4697                                    Some(delimiter.clone())
 4698                                } else {
 4699                                    None
 4700                                }
 4701                            });
 4702
 4703                            (
 4704                                comment_delimiter,
 4705                                doc_delimiter,
 4706                                insert_extra_newline,
 4707                                indent_on_newline,
 4708                                indent_on_extra_newline,
 4709                            )
 4710                        } else {
 4711                            (
 4712                                None,
 4713                                None,
 4714                                false,
 4715                                IndentSize::default(),
 4716                                IndentSize::default(),
 4717                            )
 4718                        };
 4719
 4720                        let prevent_auto_indent = doc_delimiter.is_some();
 4721                        let delimiter = comment_delimiter.or(doc_delimiter);
 4722
 4723                        let capacity_for_delimiter =
 4724                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4725                        let mut new_text = String::with_capacity(
 4726                            1 + capacity_for_delimiter
 4727                                + existing_indent.len as usize
 4728                                + indent_on_newline.len as usize
 4729                                + indent_on_extra_newline.len as usize,
 4730                        );
 4731                        new_text.push('\n');
 4732                        new_text.extend(existing_indent.chars());
 4733                        new_text.extend(indent_on_newline.chars());
 4734
 4735                        if let Some(delimiter) = &delimiter {
 4736                            new_text.push_str(delimiter);
 4737                        }
 4738
 4739                        if insert_extra_newline {
 4740                            new_text.push('\n');
 4741                            new_text.extend(existing_indent.chars());
 4742                            new_text.extend(indent_on_extra_newline.chars());
 4743                        }
 4744
 4745                        let anchor = buffer.anchor_after(end);
 4746                        let new_selection = selection.map(|_| anchor);
 4747                        (
 4748                            ((start..end, new_text), prevent_auto_indent),
 4749                            (insert_extra_newline, new_selection),
 4750                        )
 4751                    })
 4752                    .unzip()
 4753            };
 4754
 4755            let mut auto_indent_edits = Vec::new();
 4756            let mut edits = Vec::new();
 4757            for (edit, prevent_auto_indent) in edits_with_flags {
 4758                if prevent_auto_indent {
 4759                    edits.push(edit);
 4760                } else {
 4761                    auto_indent_edits.push(edit);
 4762                }
 4763            }
 4764            if !edits.is_empty() {
 4765                this.edit(edits, cx);
 4766            }
 4767            if !auto_indent_edits.is_empty() {
 4768                this.edit_with_autoindent(auto_indent_edits, cx);
 4769            }
 4770
 4771            let buffer = this.buffer.read(cx).snapshot(cx);
 4772            let new_selections = selection_info
 4773                .into_iter()
 4774                .map(|(extra_newline_inserted, new_selection)| {
 4775                    let mut cursor = new_selection.end.to_point(&buffer);
 4776                    if extra_newline_inserted {
 4777                        cursor.row -= 1;
 4778                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4779                    }
 4780                    new_selection.map(|_| cursor)
 4781                })
 4782                .collect();
 4783
 4784            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4785            this.refresh_edit_prediction(true, false, window, cx);
 4786        });
 4787    }
 4788
 4789    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4791
 4792        let buffer = self.buffer.read(cx);
 4793        let snapshot = buffer.snapshot(cx);
 4794
 4795        let mut edits = Vec::new();
 4796        let mut rows = Vec::new();
 4797
 4798        for (rows_inserted, selection) in self
 4799            .selections
 4800            .all_adjusted(&self.display_snapshot(cx))
 4801            .into_iter()
 4802            .enumerate()
 4803        {
 4804            let cursor = selection.head();
 4805            let row = cursor.row;
 4806
 4807            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4808
 4809            let newline = "\n".to_string();
 4810            edits.push((start_of_line..start_of_line, newline));
 4811
 4812            rows.push(row + rows_inserted as u32);
 4813        }
 4814
 4815        self.transact(window, cx, |editor, window, cx| {
 4816            editor.edit(edits, cx);
 4817
 4818            editor.change_selections(Default::default(), window, cx, |s| {
 4819                let mut index = 0;
 4820                s.move_cursors_with(|map, _, _| {
 4821                    let row = rows[index];
 4822                    index += 1;
 4823
 4824                    let point = Point::new(row, 0);
 4825                    let boundary = map.next_line_boundary(point).1;
 4826                    let clipped = map.clip_point(boundary, Bias::Left);
 4827
 4828                    (clipped, SelectionGoal::None)
 4829                });
 4830            });
 4831
 4832            let mut indent_edits = Vec::new();
 4833            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4834            for row in rows {
 4835                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4836                for (row, indent) in indents {
 4837                    if indent.len == 0 {
 4838                        continue;
 4839                    }
 4840
 4841                    let text = match indent.kind {
 4842                        IndentKind::Space => " ".repeat(indent.len as usize),
 4843                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4844                    };
 4845                    let point = Point::new(row.0, 0);
 4846                    indent_edits.push((point..point, text));
 4847                }
 4848            }
 4849            editor.edit(indent_edits, cx);
 4850        });
 4851    }
 4852
 4853    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4855
 4856        let buffer = self.buffer.read(cx);
 4857        let snapshot = buffer.snapshot(cx);
 4858
 4859        let mut edits = Vec::new();
 4860        let mut rows = Vec::new();
 4861        let mut rows_inserted = 0;
 4862
 4863        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4864            let cursor = selection.head();
 4865            let row = cursor.row;
 4866
 4867            let point = Point::new(row + 1, 0);
 4868            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4869
 4870            let newline = "\n".to_string();
 4871            edits.push((start_of_line..start_of_line, newline));
 4872
 4873            rows_inserted += 1;
 4874            rows.push(row + rows_inserted);
 4875        }
 4876
 4877        self.transact(window, cx, |editor, window, cx| {
 4878            editor.edit(edits, cx);
 4879
 4880            editor.change_selections(Default::default(), window, cx, |s| {
 4881                let mut index = 0;
 4882                s.move_cursors_with(|map, _, _| {
 4883                    let row = rows[index];
 4884                    index += 1;
 4885
 4886                    let point = Point::new(row, 0);
 4887                    let boundary = map.next_line_boundary(point).1;
 4888                    let clipped = map.clip_point(boundary, Bias::Left);
 4889
 4890                    (clipped, SelectionGoal::None)
 4891                });
 4892            });
 4893
 4894            let mut indent_edits = Vec::new();
 4895            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4896            for row in rows {
 4897                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4898                for (row, indent) in indents {
 4899                    if indent.len == 0 {
 4900                        continue;
 4901                    }
 4902
 4903                    let text = match indent.kind {
 4904                        IndentKind::Space => " ".repeat(indent.len as usize),
 4905                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4906                    };
 4907                    let point = Point::new(row.0, 0);
 4908                    indent_edits.push((point..point, text));
 4909                }
 4910            }
 4911            editor.edit(indent_edits, cx);
 4912        });
 4913    }
 4914
 4915    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4916        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4917            original_indent_columns: Vec::new(),
 4918        });
 4919        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4920    }
 4921
 4922    fn insert_with_autoindent_mode(
 4923        &mut self,
 4924        text: &str,
 4925        autoindent_mode: Option<AutoindentMode>,
 4926        window: &mut Window,
 4927        cx: &mut Context<Self>,
 4928    ) {
 4929        if self.read_only(cx) {
 4930            return;
 4931        }
 4932
 4933        let text: Arc<str> = text.into();
 4934        self.transact(window, cx, |this, window, cx| {
 4935            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4936            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4937                let anchors = {
 4938                    let snapshot = buffer.read(cx);
 4939                    old_selections
 4940                        .iter()
 4941                        .map(|s| {
 4942                            let anchor = snapshot.anchor_after(s.head());
 4943                            s.map(|_| anchor)
 4944                        })
 4945                        .collect::<Vec<_>>()
 4946                };
 4947                buffer.edit(
 4948                    old_selections
 4949                        .iter()
 4950                        .map(|s| (s.start..s.end, text.clone())),
 4951                    autoindent_mode,
 4952                    cx,
 4953                );
 4954                anchors
 4955            });
 4956
 4957            this.change_selections(Default::default(), window, cx, |s| {
 4958                s.select_anchors(selection_anchors);
 4959            });
 4960
 4961            cx.notify();
 4962        });
 4963    }
 4964
 4965    fn trigger_completion_on_input(
 4966        &mut self,
 4967        text: &str,
 4968        trigger_in_words: bool,
 4969        window: &mut Window,
 4970        cx: &mut Context<Self>,
 4971    ) {
 4972        let completions_source = self
 4973            .context_menu
 4974            .borrow()
 4975            .as_ref()
 4976            .and_then(|menu| match menu {
 4977                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4978                CodeContextMenu::CodeActions(_) => None,
 4979            });
 4980
 4981        match completions_source {
 4982            Some(CompletionsMenuSource::Words { .. }) => {
 4983                self.open_or_update_completions_menu(
 4984                    Some(CompletionsMenuSource::Words {
 4985                        ignore_threshold: false,
 4986                    }),
 4987                    None,
 4988                    window,
 4989                    cx,
 4990                );
 4991            }
 4992            Some(CompletionsMenuSource::Normal)
 4993            | Some(CompletionsMenuSource::SnippetChoices)
 4994            | None
 4995                if self.is_completion_trigger(
 4996                    text,
 4997                    trigger_in_words,
 4998                    completions_source.is_some(),
 4999                    cx,
 5000                ) =>
 5001            {
 5002                self.show_completions(
 5003                    &ShowCompletions {
 5004                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5005                    },
 5006                    window,
 5007                    cx,
 5008                )
 5009            }
 5010            _ => {
 5011                self.hide_context_menu(window, cx);
 5012            }
 5013        }
 5014    }
 5015
 5016    fn is_completion_trigger(
 5017        &self,
 5018        text: &str,
 5019        trigger_in_words: bool,
 5020        menu_is_open: bool,
 5021        cx: &mut Context<Self>,
 5022    ) -> bool {
 5023        let position = self.selections.newest_anchor().head();
 5024        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5025            return false;
 5026        };
 5027
 5028        if let Some(completion_provider) = &self.completion_provider {
 5029            completion_provider.is_completion_trigger(
 5030                &buffer,
 5031                position.text_anchor,
 5032                text,
 5033                trigger_in_words,
 5034                menu_is_open,
 5035                cx,
 5036            )
 5037        } else {
 5038            false
 5039        }
 5040    }
 5041
 5042    /// If any empty selections is touching the start of its innermost containing autoclose
 5043    /// region, expand it to select the brackets.
 5044    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5045        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5046        let buffer = self.buffer.read(cx).read(cx);
 5047        let new_selections = self
 5048            .selections_with_autoclose_regions(selections, &buffer)
 5049            .map(|(mut selection, region)| {
 5050                if !selection.is_empty() {
 5051                    return selection;
 5052                }
 5053
 5054                if let Some(region) = region {
 5055                    let mut range = region.range.to_offset(&buffer);
 5056                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5057                        range.start -= region.pair.start.len();
 5058                        if buffer.contains_str_at(range.start, &region.pair.start)
 5059                            && buffer.contains_str_at(range.end, &region.pair.end)
 5060                        {
 5061                            range.end += region.pair.end.len();
 5062                            selection.start = range.start;
 5063                            selection.end = range.end;
 5064
 5065                            return selection;
 5066                        }
 5067                    }
 5068                }
 5069
 5070                let always_treat_brackets_as_autoclosed = buffer
 5071                    .language_settings_at(selection.start, cx)
 5072                    .always_treat_brackets_as_autoclosed;
 5073
 5074                if !always_treat_brackets_as_autoclosed {
 5075                    return selection;
 5076                }
 5077
 5078                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5079                    for (pair, enabled) in scope.brackets() {
 5080                        if !enabled || !pair.close {
 5081                            continue;
 5082                        }
 5083
 5084                        if buffer.contains_str_at(selection.start, &pair.end) {
 5085                            let pair_start_len = pair.start.len();
 5086                            if buffer.contains_str_at(
 5087                                selection.start.saturating_sub(pair_start_len),
 5088                                &pair.start,
 5089                            ) {
 5090                                selection.start -= pair_start_len;
 5091                                selection.end += pair.end.len();
 5092
 5093                                return selection;
 5094                            }
 5095                        }
 5096                    }
 5097                }
 5098
 5099                selection
 5100            })
 5101            .collect();
 5102
 5103        drop(buffer);
 5104        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5105            selections.select(new_selections)
 5106        });
 5107    }
 5108
 5109    /// Iterate the given selections, and for each one, find the smallest surrounding
 5110    /// autoclose region. This uses the ordering of the selections and the autoclose
 5111    /// regions to avoid repeated comparisons.
 5112    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5113        &'a self,
 5114        selections: impl IntoIterator<Item = Selection<D>>,
 5115        buffer: &'a MultiBufferSnapshot,
 5116    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5117        let mut i = 0;
 5118        let mut regions = self.autoclose_regions.as_slice();
 5119        selections.into_iter().map(move |selection| {
 5120            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5121
 5122            let mut enclosing = None;
 5123            while let Some(pair_state) = regions.get(i) {
 5124                if pair_state.range.end.to_offset(buffer) < range.start {
 5125                    regions = &regions[i + 1..];
 5126                    i = 0;
 5127                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5128                    break;
 5129                } else {
 5130                    if pair_state.selection_id == selection.id {
 5131                        enclosing = Some(pair_state);
 5132                    }
 5133                    i += 1;
 5134                }
 5135            }
 5136
 5137            (selection, enclosing)
 5138        })
 5139    }
 5140
 5141    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5142    fn invalidate_autoclose_regions(
 5143        &mut self,
 5144        mut selections: &[Selection<Anchor>],
 5145        buffer: &MultiBufferSnapshot,
 5146    ) {
 5147        self.autoclose_regions.retain(|state| {
 5148            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5149                return false;
 5150            }
 5151
 5152            let mut i = 0;
 5153            while let Some(selection) = selections.get(i) {
 5154                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5155                    selections = &selections[1..];
 5156                    continue;
 5157                }
 5158                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5159                    break;
 5160                }
 5161                if selection.id == state.selection_id {
 5162                    return true;
 5163                } else {
 5164                    i += 1;
 5165                }
 5166            }
 5167            false
 5168        });
 5169    }
 5170
 5171    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5172        let offset = position.to_offset(buffer);
 5173        let (word_range, kind) =
 5174            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5175        if offset > word_range.start && kind == Some(CharKind::Word) {
 5176            Some(
 5177                buffer
 5178                    .text_for_range(word_range.start..offset)
 5179                    .collect::<String>(),
 5180            )
 5181        } else {
 5182            None
 5183        }
 5184    }
 5185
 5186    pub fn toggle_inline_values(
 5187        &mut self,
 5188        _: &ToggleInlineValues,
 5189        _: &mut Window,
 5190        cx: &mut Context<Self>,
 5191    ) {
 5192        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5193
 5194        self.refresh_inline_values(cx);
 5195    }
 5196
 5197    pub fn toggle_inlay_hints(
 5198        &mut self,
 5199        _: &ToggleInlayHints,
 5200        _: &mut Window,
 5201        cx: &mut Context<Self>,
 5202    ) {
 5203        self.refresh_inlay_hints(
 5204            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5205            cx,
 5206        );
 5207    }
 5208
 5209    pub fn inlay_hints_enabled(&self) -> bool {
 5210        self.inlay_hint_cache.enabled
 5211    }
 5212
 5213    pub fn inline_values_enabled(&self) -> bool {
 5214        self.inline_value_cache.enabled
 5215    }
 5216
 5217    #[cfg(any(test, feature = "test-support"))]
 5218    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5219        self.display_map
 5220            .read(cx)
 5221            .current_inlays()
 5222            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5223            .cloned()
 5224            .collect()
 5225    }
 5226
 5227    #[cfg(any(test, feature = "test-support"))]
 5228    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5229        self.display_map
 5230            .read(cx)
 5231            .current_inlays()
 5232            .cloned()
 5233            .collect()
 5234    }
 5235
 5236    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5237        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5238            return;
 5239        }
 5240
 5241        let reason_description = reason.description();
 5242        let ignore_debounce = matches!(
 5243            reason,
 5244            InlayHintRefreshReason::SettingsChange(_)
 5245                | InlayHintRefreshReason::Toggle(_)
 5246                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5247                | InlayHintRefreshReason::ModifiersChanged(_)
 5248        );
 5249        let (invalidate_cache, required_languages) = match reason {
 5250            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5251                match self.inlay_hint_cache.modifiers_override(enabled) {
 5252                    Some(enabled) => {
 5253                        if enabled {
 5254                            (InvalidationStrategy::RefreshRequested, None)
 5255                        } else {
 5256                            self.clear_inlay_hints(cx);
 5257                            return;
 5258                        }
 5259                    }
 5260                    None => return,
 5261                }
 5262            }
 5263            InlayHintRefreshReason::Toggle(enabled) => {
 5264                if self.inlay_hint_cache.toggle(enabled) {
 5265                    if enabled {
 5266                        (InvalidationStrategy::RefreshRequested, None)
 5267                    } else {
 5268                        self.clear_inlay_hints(cx);
 5269                        return;
 5270                    }
 5271                } else {
 5272                    return;
 5273                }
 5274            }
 5275            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5276                match self.inlay_hint_cache.update_settings(
 5277                    &self.buffer,
 5278                    new_settings,
 5279                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5280                    cx,
 5281                ) {
 5282                    ControlFlow::Break(Some(InlaySplice {
 5283                        to_remove,
 5284                        to_insert,
 5285                    })) => {
 5286                        self.splice_inlays(&to_remove, to_insert, cx);
 5287                        return;
 5288                    }
 5289                    ControlFlow::Break(None) => return,
 5290                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5291                }
 5292            }
 5293            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5294                if let Some(InlaySplice {
 5295                    to_remove,
 5296                    to_insert,
 5297                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5298                {
 5299                    self.splice_inlays(&to_remove, to_insert, cx);
 5300                }
 5301                self.display_map.update(cx, |display_map, _| {
 5302                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5303                });
 5304                return;
 5305            }
 5306            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5307            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5308                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5309            }
 5310            InlayHintRefreshReason::RefreshRequested => {
 5311                (InvalidationStrategy::RefreshRequested, None)
 5312            }
 5313        };
 5314
 5315        let mut visible_excerpts = self.visible_excerpts(required_languages.as_ref(), cx);
 5316        visible_excerpts.retain(|_, (buffer, _, _)| {
 5317            self.registered_buffers
 5318                .contains_key(&buffer.read(cx).remote_id())
 5319        });
 5320
 5321        if let Some(InlaySplice {
 5322            to_remove,
 5323            to_insert,
 5324        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5325            reason_description,
 5326            visible_excerpts,
 5327            invalidate_cache,
 5328            ignore_debounce,
 5329            cx,
 5330        ) {
 5331            self.splice_inlays(&to_remove, to_insert, cx);
 5332        }
 5333    }
 5334
 5335    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5336        self.splice_inlays(
 5337            &self
 5338                .visible_inlay_hints(cx)
 5339                .map(|inlay| inlay.id)
 5340                .collect::<Vec<_>>(),
 5341            Vec::new(),
 5342            cx,
 5343        );
 5344    }
 5345
 5346    fn visible_inlay_hints<'a>(
 5347        &'a self,
 5348        cx: &'a Context<Editor>,
 5349    ) -> impl Iterator<Item = &'a Inlay> {
 5350        self.display_map
 5351            .read(cx)
 5352            .current_inlays()
 5353            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5354    }
 5355
 5356    pub fn visible_excerpts(
 5357        &self,
 5358        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5359        cx: &mut Context<Editor>,
 5360    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5361        let Some(project) = self.project() else {
 5362            return HashMap::default();
 5363        };
 5364        let project = project.read(cx);
 5365        let multi_buffer = self.buffer().read(cx);
 5366        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5367        let multi_buffer_visible_start = self
 5368            .scroll_manager
 5369            .anchor()
 5370            .anchor
 5371            .to_point(&multi_buffer_snapshot);
 5372        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5373            multi_buffer_visible_start
 5374                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5375            Bias::Left,
 5376        );
 5377        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5378        multi_buffer_snapshot
 5379            .range_to_buffer_ranges(multi_buffer_visible_range)
 5380            .into_iter()
 5381            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5382            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5383                let buffer_file = project::File::from_dyn(buffer.file())?;
 5384                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5385                let worktree_entry = buffer_worktree
 5386                    .read(cx)
 5387                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5388                if worktree_entry.is_ignored {
 5389                    return None;
 5390                }
 5391
 5392                let language = buffer.language()?;
 5393                if let Some(restrict_to_languages) = restrict_to_languages
 5394                    && !restrict_to_languages.contains(language)
 5395                {
 5396                    return None;
 5397                }
 5398                Some((
 5399                    excerpt_id,
 5400                    (
 5401                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5402                        buffer.version().clone(),
 5403                        excerpt_visible_range,
 5404                    ),
 5405                ))
 5406            })
 5407            .collect()
 5408    }
 5409
 5410    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5411        TextLayoutDetails {
 5412            text_system: window.text_system().clone(),
 5413            editor_style: self.style.clone().unwrap(),
 5414            rem_size: window.rem_size(),
 5415            scroll_anchor: self.scroll_manager.anchor(),
 5416            visible_rows: self.visible_line_count(),
 5417            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5418        }
 5419    }
 5420
 5421    pub fn splice_inlays(
 5422        &self,
 5423        to_remove: &[InlayId],
 5424        to_insert: Vec<Inlay>,
 5425        cx: &mut Context<Self>,
 5426    ) {
 5427        self.display_map.update(cx, |display_map, cx| {
 5428            display_map.splice_inlays(to_remove, to_insert, cx)
 5429        });
 5430        cx.notify();
 5431    }
 5432
 5433    fn trigger_on_type_formatting(
 5434        &self,
 5435        input: String,
 5436        window: &mut Window,
 5437        cx: &mut Context<Self>,
 5438    ) -> Option<Task<Result<()>>> {
 5439        if input.len() != 1 {
 5440            return None;
 5441        }
 5442
 5443        let project = self.project()?;
 5444        let position = self.selections.newest_anchor().head();
 5445        let (buffer, buffer_position) = self
 5446            .buffer
 5447            .read(cx)
 5448            .text_anchor_for_position(position, cx)?;
 5449
 5450        let settings = language_settings::language_settings(
 5451            buffer
 5452                .read(cx)
 5453                .language_at(buffer_position)
 5454                .map(|l| l.name()),
 5455            buffer.read(cx).file(),
 5456            cx,
 5457        );
 5458        if !settings.use_on_type_format {
 5459            return None;
 5460        }
 5461
 5462        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5463        // hence we do LSP request & edit on host side only — add formats to host's history.
 5464        let push_to_lsp_host_history = true;
 5465        // If this is not the host, append its history with new edits.
 5466        let push_to_client_history = project.read(cx).is_via_collab();
 5467
 5468        let on_type_formatting = project.update(cx, |project, cx| {
 5469            project.on_type_format(
 5470                buffer.clone(),
 5471                buffer_position,
 5472                input,
 5473                push_to_lsp_host_history,
 5474                cx,
 5475            )
 5476        });
 5477        Some(cx.spawn_in(window, async move |editor, cx| {
 5478            if let Some(transaction) = on_type_formatting.await? {
 5479                if push_to_client_history {
 5480                    buffer
 5481                        .update(cx, |buffer, _| {
 5482                            buffer.push_transaction(transaction, Instant::now());
 5483                            buffer.finalize_last_transaction();
 5484                        })
 5485                        .ok();
 5486                }
 5487                editor.update(cx, |editor, cx| {
 5488                    editor.refresh_document_highlights(cx);
 5489                })?;
 5490            }
 5491            Ok(())
 5492        }))
 5493    }
 5494
 5495    pub fn show_word_completions(
 5496        &mut self,
 5497        _: &ShowWordCompletions,
 5498        window: &mut Window,
 5499        cx: &mut Context<Self>,
 5500    ) {
 5501        self.open_or_update_completions_menu(
 5502            Some(CompletionsMenuSource::Words {
 5503                ignore_threshold: true,
 5504            }),
 5505            None,
 5506            window,
 5507            cx,
 5508        );
 5509    }
 5510
 5511    pub fn show_completions(
 5512        &mut self,
 5513        options: &ShowCompletions,
 5514        window: &mut Window,
 5515        cx: &mut Context<Self>,
 5516    ) {
 5517        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5518    }
 5519
 5520    fn open_or_update_completions_menu(
 5521        &mut self,
 5522        requested_source: Option<CompletionsMenuSource>,
 5523        trigger: Option<&str>,
 5524        window: &mut Window,
 5525        cx: &mut Context<Self>,
 5526    ) {
 5527        if self.pending_rename.is_some() {
 5528            return;
 5529        }
 5530
 5531        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5532
 5533        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5534        // inserted and selected. To handle that case, the start of the selection is used so that
 5535        // the menu starts with all choices.
 5536        let position = self
 5537            .selections
 5538            .newest_anchor()
 5539            .start
 5540            .bias_right(&multibuffer_snapshot);
 5541        if position.diff_base_anchor.is_some() {
 5542            return;
 5543        }
 5544        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5545        let Some(buffer) = buffer_position
 5546            .buffer_id
 5547            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5548        else {
 5549            return;
 5550        };
 5551        let buffer_snapshot = buffer.read(cx).snapshot();
 5552
 5553        let query: Option<Arc<String>> =
 5554            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5555                .map(|query| query.into());
 5556
 5557        drop(multibuffer_snapshot);
 5558
 5559        // Hide the current completions menu when query is empty. Without this, cached
 5560        // completions from before the trigger char may be reused (#32774).
 5561        if query.is_none() {
 5562            let menu_is_open = matches!(
 5563                self.context_menu.borrow().as_ref(),
 5564                Some(CodeContextMenu::Completions(_))
 5565            );
 5566            if menu_is_open {
 5567                self.hide_context_menu(window, cx);
 5568            }
 5569        }
 5570
 5571        let mut ignore_word_threshold = false;
 5572        let provider = match requested_source {
 5573            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5574            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5575                ignore_word_threshold = ignore_threshold;
 5576                None
 5577            }
 5578            Some(CompletionsMenuSource::SnippetChoices) => {
 5579                log::error!("bug: SnippetChoices requested_source is not handled");
 5580                None
 5581            }
 5582        };
 5583
 5584        let sort_completions = provider
 5585            .as_ref()
 5586            .is_some_and(|provider| provider.sort_completions());
 5587
 5588        let filter_completions = provider
 5589            .as_ref()
 5590            .is_none_or(|provider| provider.filter_completions());
 5591
 5592        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5593            if filter_completions {
 5594                menu.filter(query.clone(), provider.clone(), window, cx);
 5595            }
 5596            // When `is_incomplete` is false, no need to re-query completions when the current query
 5597            // is a suffix of the initial query.
 5598            if !menu.is_incomplete {
 5599                // If the new query is a suffix of the old query (typing more characters) and
 5600                // the previous result was complete, the existing completions can be filtered.
 5601                //
 5602                // Note that this is always true for snippet completions.
 5603                let query_matches = match (&menu.initial_query, &query) {
 5604                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5605                    (None, _) => true,
 5606                    _ => false,
 5607                };
 5608                if query_matches {
 5609                    let position_matches = if menu.initial_position == position {
 5610                        true
 5611                    } else {
 5612                        let snapshot = self.buffer.read(cx).read(cx);
 5613                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5614                    };
 5615                    if position_matches {
 5616                        return;
 5617                    }
 5618                }
 5619            }
 5620        };
 5621
 5622        let trigger_kind = match trigger {
 5623            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5624                CompletionTriggerKind::TRIGGER_CHARACTER
 5625            }
 5626            _ => CompletionTriggerKind::INVOKED,
 5627        };
 5628        let completion_context = CompletionContext {
 5629            trigger_character: trigger.and_then(|trigger| {
 5630                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5631                    Some(String::from(trigger))
 5632                } else {
 5633                    None
 5634                }
 5635            }),
 5636            trigger_kind,
 5637        };
 5638
 5639        let Anchor {
 5640            excerpt_id: buffer_excerpt_id,
 5641            text_anchor: buffer_position,
 5642            ..
 5643        } = buffer_position;
 5644
 5645        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5646            buffer_snapshot.surrounding_word(buffer_position, None)
 5647        {
 5648            let word_to_exclude = buffer_snapshot
 5649                .text_for_range(word_range.clone())
 5650                .collect::<String>();
 5651            (
 5652                buffer_snapshot.anchor_before(word_range.start)
 5653                    ..buffer_snapshot.anchor_after(buffer_position),
 5654                Some(word_to_exclude),
 5655            )
 5656        } else {
 5657            (buffer_position..buffer_position, None)
 5658        };
 5659
 5660        let language = buffer_snapshot
 5661            .language_at(buffer_position)
 5662            .map(|language| language.name());
 5663
 5664        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5665            .completions
 5666            .clone();
 5667
 5668        let show_completion_documentation = buffer_snapshot
 5669            .settings_at(buffer_position, cx)
 5670            .show_completion_documentation;
 5671
 5672        // The document can be large, so stay in reasonable bounds when searching for words,
 5673        // otherwise completion pop-up might be slow to appear.
 5674        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5675        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5676        let min_word_search = buffer_snapshot.clip_point(
 5677            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5678            Bias::Left,
 5679        );
 5680        let max_word_search = buffer_snapshot.clip_point(
 5681            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5682            Bias::Right,
 5683        );
 5684        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5685            ..buffer_snapshot.point_to_offset(max_word_search);
 5686
 5687        let skip_digits = query
 5688            .as_ref()
 5689            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5690
 5691        let omit_word_completions = !self.word_completions_enabled
 5692            || (!ignore_word_threshold
 5693                && match &query {
 5694                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5695                    None => completion_settings.words_min_length != 0,
 5696                });
 5697
 5698        let (mut words, provider_responses) = match &provider {
 5699            Some(provider) => {
 5700                let provider_responses = provider.completions(
 5701                    buffer_excerpt_id,
 5702                    &buffer,
 5703                    buffer_position,
 5704                    completion_context,
 5705                    window,
 5706                    cx,
 5707                );
 5708
 5709                let words = match (omit_word_completions, completion_settings.words) {
 5710                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5711                        Task::ready(BTreeMap::default())
 5712                    }
 5713                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5714                        .background_spawn(async move {
 5715                            buffer_snapshot.words_in_range(WordsQuery {
 5716                                fuzzy_contents: None,
 5717                                range: word_search_range,
 5718                                skip_digits,
 5719                            })
 5720                        }),
 5721                };
 5722
 5723                (words, provider_responses)
 5724            }
 5725            None => {
 5726                let words = if omit_word_completions {
 5727                    Task::ready(BTreeMap::default())
 5728                } else {
 5729                    cx.background_spawn(async move {
 5730                        buffer_snapshot.words_in_range(WordsQuery {
 5731                            fuzzy_contents: None,
 5732                            range: word_search_range,
 5733                            skip_digits,
 5734                        })
 5735                    })
 5736                };
 5737                (words, Task::ready(Ok(Vec::new())))
 5738            }
 5739        };
 5740
 5741        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5742
 5743        let id = post_inc(&mut self.next_completion_id);
 5744        let task = cx.spawn_in(window, async move |editor, cx| {
 5745            let Ok(()) = editor.update(cx, |this, _| {
 5746                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5747            }) else {
 5748                return;
 5749            };
 5750
 5751            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5752            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5753            let mut completions = Vec::new();
 5754            let mut is_incomplete = false;
 5755            let mut display_options: Option<CompletionDisplayOptions> = None;
 5756            if let Some(provider_responses) = provider_responses.await.log_err()
 5757                && !provider_responses.is_empty()
 5758            {
 5759                for response in provider_responses {
 5760                    completions.extend(response.completions);
 5761                    is_incomplete = is_incomplete || response.is_incomplete;
 5762                    match display_options.as_mut() {
 5763                        None => {
 5764                            display_options = Some(response.display_options);
 5765                        }
 5766                        Some(options) => options.merge(&response.display_options),
 5767                    }
 5768                }
 5769                if completion_settings.words == WordsCompletionMode::Fallback {
 5770                    words = Task::ready(BTreeMap::default());
 5771                }
 5772            }
 5773            let display_options = display_options.unwrap_or_default();
 5774
 5775            let mut words = words.await;
 5776            if let Some(word_to_exclude) = &word_to_exclude {
 5777                words.remove(word_to_exclude);
 5778            }
 5779            for lsp_completion in &completions {
 5780                words.remove(&lsp_completion.new_text);
 5781            }
 5782            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5783                replace_range: word_replace_range.clone(),
 5784                new_text: word.clone(),
 5785                label: CodeLabel::plain(word, None),
 5786                icon_path: None,
 5787                documentation: None,
 5788                source: CompletionSource::BufferWord {
 5789                    word_range,
 5790                    resolved: false,
 5791                },
 5792                insert_text_mode: Some(InsertTextMode::AS_IS),
 5793                confirm: None,
 5794            }));
 5795
 5796            let menu = if completions.is_empty() {
 5797                None
 5798            } else {
 5799                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5800                    let languages = editor
 5801                        .workspace
 5802                        .as_ref()
 5803                        .and_then(|(workspace, _)| workspace.upgrade())
 5804                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5805                    let menu = CompletionsMenu::new(
 5806                        id,
 5807                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5808                        sort_completions,
 5809                        show_completion_documentation,
 5810                        position,
 5811                        query.clone(),
 5812                        is_incomplete,
 5813                        buffer.clone(),
 5814                        completions.into(),
 5815                        display_options,
 5816                        snippet_sort_order,
 5817                        languages,
 5818                        language,
 5819                        cx,
 5820                    );
 5821
 5822                    let query = if filter_completions { query } else { None };
 5823                    let matches_task = if let Some(query) = query {
 5824                        menu.do_async_filtering(query, cx)
 5825                    } else {
 5826                        Task::ready(menu.unfiltered_matches())
 5827                    };
 5828                    (menu, matches_task)
 5829                }) else {
 5830                    return;
 5831                };
 5832
 5833                let matches = matches_task.await;
 5834
 5835                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5836                    // Newer menu already set, so exit.
 5837                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5838                        editor.context_menu.borrow().as_ref()
 5839                        && prev_menu.id > id
 5840                    {
 5841                        return;
 5842                    };
 5843
 5844                    // Only valid to take prev_menu because it the new menu is immediately set
 5845                    // below, or the menu is hidden.
 5846                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5847                        editor.context_menu.borrow_mut().take()
 5848                    {
 5849                        let position_matches =
 5850                            if prev_menu.initial_position == menu.initial_position {
 5851                                true
 5852                            } else {
 5853                                let snapshot = editor.buffer.read(cx).read(cx);
 5854                                prev_menu.initial_position.to_offset(&snapshot)
 5855                                    == menu.initial_position.to_offset(&snapshot)
 5856                            };
 5857                        if position_matches {
 5858                            // Preserve markdown cache before `set_filter_results` because it will
 5859                            // try to populate the documentation cache.
 5860                            menu.preserve_markdown_cache(prev_menu);
 5861                        }
 5862                    };
 5863
 5864                    menu.set_filter_results(matches, provider, window, cx);
 5865                }) else {
 5866                    return;
 5867                };
 5868
 5869                menu.visible().then_some(menu)
 5870            };
 5871
 5872            editor
 5873                .update_in(cx, |editor, window, cx| {
 5874                    if editor.focus_handle.is_focused(window)
 5875                        && let Some(menu) = menu
 5876                    {
 5877                        *editor.context_menu.borrow_mut() =
 5878                            Some(CodeContextMenu::Completions(menu));
 5879
 5880                        crate::hover_popover::hide_hover(editor, cx);
 5881                        if editor.show_edit_predictions_in_menu() {
 5882                            editor.update_visible_edit_prediction(window, cx);
 5883                        } else {
 5884                            editor.discard_edit_prediction(false, cx);
 5885                        }
 5886
 5887                        cx.notify();
 5888                        return;
 5889                    }
 5890
 5891                    if editor.completion_tasks.len() <= 1 {
 5892                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5893                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5894                        // If it was already hidden and we don't show edit predictions in the menu,
 5895                        // we should also show the edit prediction when available.
 5896                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5897                            editor.update_visible_edit_prediction(window, cx);
 5898                        }
 5899                    }
 5900                })
 5901                .ok();
 5902        });
 5903
 5904        self.completion_tasks.push((id, task));
 5905    }
 5906
 5907    #[cfg(feature = "test-support")]
 5908    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5909        let menu = self.context_menu.borrow();
 5910        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5911            let completions = menu.completions.borrow();
 5912            Some(completions.to_vec())
 5913        } else {
 5914            None
 5915        }
 5916    }
 5917
 5918    pub fn with_completions_menu_matching_id<R>(
 5919        &self,
 5920        id: CompletionId,
 5921        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5922    ) -> R {
 5923        let mut context_menu = self.context_menu.borrow_mut();
 5924        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5925            return f(None);
 5926        };
 5927        if completions_menu.id != id {
 5928            return f(None);
 5929        }
 5930        f(Some(completions_menu))
 5931    }
 5932
 5933    pub fn confirm_completion(
 5934        &mut self,
 5935        action: &ConfirmCompletion,
 5936        window: &mut Window,
 5937        cx: &mut Context<Self>,
 5938    ) -> Option<Task<Result<()>>> {
 5939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5940        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5941    }
 5942
 5943    pub fn confirm_completion_insert(
 5944        &mut self,
 5945        _: &ConfirmCompletionInsert,
 5946        window: &mut Window,
 5947        cx: &mut Context<Self>,
 5948    ) -> Option<Task<Result<()>>> {
 5949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5950        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5951    }
 5952
 5953    pub fn confirm_completion_replace(
 5954        &mut self,
 5955        _: &ConfirmCompletionReplace,
 5956        window: &mut Window,
 5957        cx: &mut Context<Self>,
 5958    ) -> Option<Task<Result<()>>> {
 5959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5960        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5961    }
 5962
 5963    pub fn compose_completion(
 5964        &mut self,
 5965        action: &ComposeCompletion,
 5966        window: &mut Window,
 5967        cx: &mut Context<Self>,
 5968    ) -> Option<Task<Result<()>>> {
 5969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5970        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5971    }
 5972
 5973    fn do_completion(
 5974        &mut self,
 5975        item_ix: Option<usize>,
 5976        intent: CompletionIntent,
 5977        window: &mut Window,
 5978        cx: &mut Context<Editor>,
 5979    ) -> Option<Task<Result<()>>> {
 5980        use language::ToOffset as _;
 5981
 5982        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5983        else {
 5984            return None;
 5985        };
 5986
 5987        let candidate_id = {
 5988            let entries = completions_menu.entries.borrow();
 5989            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5990            if self.show_edit_predictions_in_menu() {
 5991                self.discard_edit_prediction(true, cx);
 5992            }
 5993            mat.candidate_id
 5994        };
 5995
 5996        let completion = completions_menu
 5997            .completions
 5998            .borrow()
 5999            .get(candidate_id)?
 6000            .clone();
 6001        cx.stop_propagation();
 6002
 6003        let buffer_handle = completions_menu.buffer.clone();
 6004
 6005        let CompletionEdit {
 6006            new_text,
 6007            snippet,
 6008            replace_range,
 6009        } = process_completion_for_edit(
 6010            &completion,
 6011            intent,
 6012            &buffer_handle,
 6013            &completions_menu.initial_position.text_anchor,
 6014            cx,
 6015        );
 6016
 6017        let buffer = buffer_handle.read(cx);
 6018        let snapshot = self.buffer.read(cx).snapshot(cx);
 6019        let newest_anchor = self.selections.newest_anchor();
 6020        let replace_range_multibuffer = {
 6021            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6022            excerpt.map_range_from_buffer(replace_range.clone())
 6023        };
 6024        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6025            return None;
 6026        }
 6027
 6028        let old_text = buffer
 6029            .text_for_range(replace_range.clone())
 6030            .collect::<String>();
 6031        let lookbehind = newest_anchor
 6032            .start
 6033            .text_anchor
 6034            .to_offset(buffer)
 6035            .saturating_sub(replace_range.start);
 6036        let lookahead = replace_range
 6037            .end
 6038            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6039        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6040        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6041
 6042        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6043        let mut ranges = Vec::new();
 6044        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6045
 6046        for selection in &selections {
 6047            let range = if selection.id == newest_anchor.id {
 6048                replace_range_multibuffer.clone()
 6049            } else {
 6050                let mut range = selection.range();
 6051
 6052                // if prefix is present, don't duplicate it
 6053                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6054                    range.start = range.start.saturating_sub(lookbehind);
 6055
 6056                    // if suffix is also present, mimic the newest cursor and replace it
 6057                    if selection.id != newest_anchor.id
 6058                        && snapshot.contains_str_at(range.end, suffix)
 6059                    {
 6060                        range.end += lookahead;
 6061                    }
 6062                }
 6063                range
 6064            };
 6065
 6066            ranges.push(range.clone());
 6067
 6068            if !self.linked_edit_ranges.is_empty() {
 6069                let start_anchor = snapshot.anchor_before(range.start);
 6070                let end_anchor = snapshot.anchor_after(range.end);
 6071                if let Some(ranges) = self
 6072                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6073                {
 6074                    for (buffer, edits) in ranges {
 6075                        linked_edits
 6076                            .entry(buffer.clone())
 6077                            .or_default()
 6078                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6079                    }
 6080                }
 6081            }
 6082        }
 6083
 6084        let common_prefix_len = old_text
 6085            .chars()
 6086            .zip(new_text.chars())
 6087            .take_while(|(a, b)| a == b)
 6088            .map(|(a, _)| a.len_utf8())
 6089            .sum::<usize>();
 6090
 6091        cx.emit(EditorEvent::InputHandled {
 6092            utf16_range_to_replace: None,
 6093            text: new_text[common_prefix_len..].into(),
 6094        });
 6095
 6096        self.transact(window, cx, |editor, window, cx| {
 6097            if let Some(mut snippet) = snippet {
 6098                snippet.text = new_text.to_string();
 6099                editor
 6100                    .insert_snippet(&ranges, snippet, window, cx)
 6101                    .log_err();
 6102            } else {
 6103                editor.buffer.update(cx, |multi_buffer, cx| {
 6104                    let auto_indent = match completion.insert_text_mode {
 6105                        Some(InsertTextMode::AS_IS) => None,
 6106                        _ => editor.autoindent_mode.clone(),
 6107                    };
 6108                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6109                    multi_buffer.edit(edits, auto_indent, cx);
 6110                });
 6111            }
 6112            for (buffer, edits) in linked_edits {
 6113                buffer.update(cx, |buffer, cx| {
 6114                    let snapshot = buffer.snapshot();
 6115                    let edits = edits
 6116                        .into_iter()
 6117                        .map(|(range, text)| {
 6118                            use text::ToPoint as TP;
 6119                            let end_point = TP::to_point(&range.end, &snapshot);
 6120                            let start_point = TP::to_point(&range.start, &snapshot);
 6121                            (start_point..end_point, text)
 6122                        })
 6123                        .sorted_by_key(|(range, _)| range.start);
 6124                    buffer.edit(edits, None, cx);
 6125                })
 6126            }
 6127
 6128            editor.refresh_edit_prediction(true, false, window, cx);
 6129        });
 6130        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6131
 6132        let show_new_completions_on_confirm = completion
 6133            .confirm
 6134            .as_ref()
 6135            .is_some_and(|confirm| confirm(intent, window, cx));
 6136        if show_new_completions_on_confirm {
 6137            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6138        }
 6139
 6140        let provider = self.completion_provider.as_ref()?;
 6141        drop(completion);
 6142        let apply_edits = provider.apply_additional_edits_for_completion(
 6143            buffer_handle,
 6144            completions_menu.completions.clone(),
 6145            candidate_id,
 6146            true,
 6147            cx,
 6148        );
 6149
 6150        let editor_settings = EditorSettings::get_global(cx);
 6151        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6152            // After the code completion is finished, users often want to know what signatures are needed.
 6153            // so we should automatically call signature_help
 6154            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6155        }
 6156
 6157        Some(cx.foreground_executor().spawn(async move {
 6158            apply_edits.await?;
 6159            Ok(())
 6160        }))
 6161    }
 6162
 6163    pub fn toggle_code_actions(
 6164        &mut self,
 6165        action: &ToggleCodeActions,
 6166        window: &mut Window,
 6167        cx: &mut Context<Self>,
 6168    ) {
 6169        let quick_launch = action.quick_launch;
 6170        let mut context_menu = self.context_menu.borrow_mut();
 6171        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6172            if code_actions.deployed_from == action.deployed_from {
 6173                // Toggle if we're selecting the same one
 6174                *context_menu = None;
 6175                cx.notify();
 6176                return;
 6177            } else {
 6178                // Otherwise, clear it and start a new one
 6179                *context_menu = None;
 6180                cx.notify();
 6181            }
 6182        }
 6183        drop(context_menu);
 6184        let snapshot = self.snapshot(window, cx);
 6185        let deployed_from = action.deployed_from.clone();
 6186        let action = action.clone();
 6187        self.completion_tasks.clear();
 6188        self.discard_edit_prediction(false, cx);
 6189
 6190        let multibuffer_point = match &action.deployed_from {
 6191            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6192                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6193            }
 6194            _ => self
 6195                .selections
 6196                .newest::<Point>(&snapshot.display_snapshot)
 6197                .head(),
 6198        };
 6199        let Some((buffer, buffer_row)) = snapshot
 6200            .buffer_snapshot()
 6201            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6202            .and_then(|(buffer_snapshot, range)| {
 6203                self.buffer()
 6204                    .read(cx)
 6205                    .buffer(buffer_snapshot.remote_id())
 6206                    .map(|buffer| (buffer, range.start.row))
 6207            })
 6208        else {
 6209            return;
 6210        };
 6211        let buffer_id = buffer.read(cx).remote_id();
 6212        let tasks = self
 6213            .tasks
 6214            .get(&(buffer_id, buffer_row))
 6215            .map(|t| Arc::new(t.to_owned()));
 6216
 6217        if !self.focus_handle.is_focused(window) {
 6218            return;
 6219        }
 6220        let project = self.project.clone();
 6221
 6222        let code_actions_task = match deployed_from {
 6223            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6224            _ => self.code_actions(buffer_row, window, cx),
 6225        };
 6226
 6227        let runnable_task = match deployed_from {
 6228            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6229            _ => {
 6230                let mut task_context_task = Task::ready(None);
 6231                if let Some(tasks) = &tasks
 6232                    && let Some(project) = project
 6233                {
 6234                    task_context_task =
 6235                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6236                }
 6237
 6238                cx.spawn_in(window, {
 6239                    let buffer = buffer.clone();
 6240                    async move |editor, cx| {
 6241                        let task_context = task_context_task.await;
 6242
 6243                        let resolved_tasks =
 6244                            tasks
 6245                                .zip(task_context.clone())
 6246                                .map(|(tasks, task_context)| ResolvedTasks {
 6247                                    templates: tasks.resolve(&task_context).collect(),
 6248                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6249                                        multibuffer_point.row,
 6250                                        tasks.column,
 6251                                    )),
 6252                                });
 6253                        let debug_scenarios = editor
 6254                            .update(cx, |editor, cx| {
 6255                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6256                            })?
 6257                            .await;
 6258                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6259                    }
 6260                })
 6261            }
 6262        };
 6263
 6264        cx.spawn_in(window, async move |editor, cx| {
 6265            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6266            let code_actions = code_actions_task.await;
 6267            let spawn_straight_away = quick_launch
 6268                && resolved_tasks
 6269                    .as_ref()
 6270                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6271                && code_actions
 6272                    .as_ref()
 6273                    .is_none_or(|actions| actions.is_empty())
 6274                && debug_scenarios.is_empty();
 6275
 6276            editor.update_in(cx, |editor, window, cx| {
 6277                crate::hover_popover::hide_hover(editor, cx);
 6278                let actions = CodeActionContents::new(
 6279                    resolved_tasks,
 6280                    code_actions,
 6281                    debug_scenarios,
 6282                    task_context.unwrap_or_default(),
 6283                );
 6284
 6285                // Don't show the menu if there are no actions available
 6286                if actions.is_empty() {
 6287                    cx.notify();
 6288                    return Task::ready(Ok(()));
 6289                }
 6290
 6291                *editor.context_menu.borrow_mut() =
 6292                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6293                        buffer,
 6294                        actions,
 6295                        selected_item: Default::default(),
 6296                        scroll_handle: UniformListScrollHandle::default(),
 6297                        deployed_from,
 6298                    }));
 6299                cx.notify();
 6300                if spawn_straight_away
 6301                    && let Some(task) = editor.confirm_code_action(
 6302                        &ConfirmCodeAction { item_ix: Some(0) },
 6303                        window,
 6304                        cx,
 6305                    )
 6306                {
 6307                    return task;
 6308                }
 6309
 6310                Task::ready(Ok(()))
 6311            })
 6312        })
 6313        .detach_and_log_err(cx);
 6314    }
 6315
 6316    fn debug_scenarios(
 6317        &mut self,
 6318        resolved_tasks: &Option<ResolvedTasks>,
 6319        buffer: &Entity<Buffer>,
 6320        cx: &mut App,
 6321    ) -> Task<Vec<task::DebugScenario>> {
 6322        maybe!({
 6323            let project = self.project()?;
 6324            let dap_store = project.read(cx).dap_store();
 6325            let mut scenarios = vec![];
 6326            let resolved_tasks = resolved_tasks.as_ref()?;
 6327            let buffer = buffer.read(cx);
 6328            let language = buffer.language()?;
 6329            let file = buffer.file();
 6330            let debug_adapter = language_settings(language.name().into(), file, cx)
 6331                .debuggers
 6332                .first()
 6333                .map(SharedString::from)
 6334                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6335
 6336            dap_store.update(cx, |dap_store, cx| {
 6337                for (_, task) in &resolved_tasks.templates {
 6338                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6339                        task.original_task().clone(),
 6340                        debug_adapter.clone().into(),
 6341                        task.display_label().to_owned().into(),
 6342                        cx,
 6343                    );
 6344                    scenarios.push(maybe_scenario);
 6345                }
 6346            });
 6347            Some(cx.background_spawn(async move {
 6348                futures::future::join_all(scenarios)
 6349                    .await
 6350                    .into_iter()
 6351                    .flatten()
 6352                    .collect::<Vec<_>>()
 6353            }))
 6354        })
 6355        .unwrap_or_else(|| Task::ready(vec![]))
 6356    }
 6357
 6358    fn code_actions(
 6359        &mut self,
 6360        buffer_row: u32,
 6361        window: &mut Window,
 6362        cx: &mut Context<Self>,
 6363    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6364        let mut task = self.code_actions_task.take();
 6365        cx.spawn_in(window, async move |editor, cx| {
 6366            while let Some(prev_task) = task {
 6367                prev_task.await.log_err();
 6368                task = editor
 6369                    .update(cx, |this, _| this.code_actions_task.take())
 6370                    .ok()?;
 6371            }
 6372
 6373            editor
 6374                .update(cx, |editor, cx| {
 6375                    editor
 6376                        .available_code_actions
 6377                        .clone()
 6378                        .and_then(|(location, code_actions)| {
 6379                            let snapshot = location.buffer.read(cx).snapshot();
 6380                            let point_range = location.range.to_point(&snapshot);
 6381                            let point_range = point_range.start.row..=point_range.end.row;
 6382                            if point_range.contains(&buffer_row) {
 6383                                Some(code_actions)
 6384                            } else {
 6385                                None
 6386                            }
 6387                        })
 6388                })
 6389                .ok()
 6390                .flatten()
 6391        })
 6392    }
 6393
 6394    pub fn confirm_code_action(
 6395        &mut self,
 6396        action: &ConfirmCodeAction,
 6397        window: &mut Window,
 6398        cx: &mut Context<Self>,
 6399    ) -> Option<Task<Result<()>>> {
 6400        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6401
 6402        let actions_menu =
 6403            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6404                menu
 6405            } else {
 6406                return None;
 6407            };
 6408
 6409        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6410        let action = actions_menu.actions.get(action_ix)?;
 6411        let title = action.label();
 6412        let buffer = actions_menu.buffer;
 6413        let workspace = self.workspace()?;
 6414
 6415        match action {
 6416            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6417                workspace.update(cx, |workspace, cx| {
 6418                    workspace.schedule_resolved_task(
 6419                        task_source_kind,
 6420                        resolved_task,
 6421                        false,
 6422                        window,
 6423                        cx,
 6424                    );
 6425
 6426                    Some(Task::ready(Ok(())))
 6427                })
 6428            }
 6429            CodeActionsItem::CodeAction {
 6430                excerpt_id,
 6431                action,
 6432                provider,
 6433            } => {
 6434                let apply_code_action =
 6435                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6436                let workspace = workspace.downgrade();
 6437                Some(cx.spawn_in(window, async move |editor, cx| {
 6438                    let project_transaction = apply_code_action.await?;
 6439                    Self::open_project_transaction(
 6440                        &editor,
 6441                        workspace,
 6442                        project_transaction,
 6443                        title,
 6444                        cx,
 6445                    )
 6446                    .await
 6447                }))
 6448            }
 6449            CodeActionsItem::DebugScenario(scenario) => {
 6450                let context = actions_menu.actions.context;
 6451
 6452                workspace.update(cx, |workspace, cx| {
 6453                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6454                    workspace.start_debug_session(
 6455                        scenario,
 6456                        context,
 6457                        Some(buffer),
 6458                        None,
 6459                        window,
 6460                        cx,
 6461                    );
 6462                });
 6463                Some(Task::ready(Ok(())))
 6464            }
 6465        }
 6466    }
 6467
 6468    pub async fn open_project_transaction(
 6469        editor: &WeakEntity<Editor>,
 6470        workspace: WeakEntity<Workspace>,
 6471        transaction: ProjectTransaction,
 6472        title: String,
 6473        cx: &mut AsyncWindowContext,
 6474    ) -> Result<()> {
 6475        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6476        cx.update(|_, cx| {
 6477            entries.sort_unstable_by_key(|(buffer, _)| {
 6478                buffer.read(cx).file().map(|f| f.path().clone())
 6479            });
 6480        })?;
 6481        if entries.is_empty() {
 6482            return Ok(());
 6483        }
 6484
 6485        // If the project transaction's edits are all contained within this editor, then
 6486        // avoid opening a new editor to display them.
 6487
 6488        if let [(buffer, transaction)] = &*entries {
 6489            let excerpt = editor.update(cx, |editor, cx| {
 6490                editor
 6491                    .buffer()
 6492                    .read(cx)
 6493                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6494            })?;
 6495            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6496                && excerpted_buffer == *buffer
 6497            {
 6498                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6499                    let excerpt_range = excerpt_range.to_offset(buffer);
 6500                    buffer
 6501                        .edited_ranges_for_transaction::<usize>(transaction)
 6502                        .all(|range| {
 6503                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6504                        })
 6505                })?;
 6506
 6507                if all_edits_within_excerpt {
 6508                    return Ok(());
 6509                }
 6510            }
 6511        }
 6512
 6513        let mut ranges_to_highlight = Vec::new();
 6514        let excerpt_buffer = cx.new(|cx| {
 6515            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6516            for (buffer_handle, transaction) in &entries {
 6517                let edited_ranges = buffer_handle
 6518                    .read(cx)
 6519                    .edited_ranges_for_transaction::<Point>(transaction)
 6520                    .collect::<Vec<_>>();
 6521                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6522                    PathKey::for_buffer(buffer_handle, cx),
 6523                    buffer_handle.clone(),
 6524                    edited_ranges,
 6525                    multibuffer_context_lines(cx),
 6526                    cx,
 6527                );
 6528
 6529                ranges_to_highlight.extend(ranges);
 6530            }
 6531            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6532            multibuffer
 6533        })?;
 6534
 6535        workspace.update_in(cx, |workspace, window, cx| {
 6536            let project = workspace.project().clone();
 6537            let editor =
 6538                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6539            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6540            editor.update(cx, |editor, cx| {
 6541                editor.highlight_background::<Self>(
 6542                    &ranges_to_highlight,
 6543                    |theme| theme.colors().editor_highlighted_line_background,
 6544                    cx,
 6545                );
 6546            });
 6547        })?;
 6548
 6549        Ok(())
 6550    }
 6551
 6552    pub fn clear_code_action_providers(&mut self) {
 6553        self.code_action_providers.clear();
 6554        self.available_code_actions.take();
 6555    }
 6556
 6557    pub fn add_code_action_provider(
 6558        &mut self,
 6559        provider: Rc<dyn CodeActionProvider>,
 6560        window: &mut Window,
 6561        cx: &mut Context<Self>,
 6562    ) {
 6563        if self
 6564            .code_action_providers
 6565            .iter()
 6566            .any(|existing_provider| existing_provider.id() == provider.id())
 6567        {
 6568            return;
 6569        }
 6570
 6571        self.code_action_providers.push(provider);
 6572        self.refresh_code_actions(window, cx);
 6573    }
 6574
 6575    pub fn remove_code_action_provider(
 6576        &mut self,
 6577        id: Arc<str>,
 6578        window: &mut Window,
 6579        cx: &mut Context<Self>,
 6580    ) {
 6581        self.code_action_providers
 6582            .retain(|provider| provider.id() != id);
 6583        self.refresh_code_actions(window, cx);
 6584    }
 6585
 6586    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6587        !self.code_action_providers.is_empty()
 6588            && EditorSettings::get_global(cx).toolbar.code_actions
 6589    }
 6590
 6591    pub fn has_available_code_actions(&self) -> bool {
 6592        self.available_code_actions
 6593            .as_ref()
 6594            .is_some_and(|(_, actions)| !actions.is_empty())
 6595    }
 6596
 6597    fn render_inline_code_actions(
 6598        &self,
 6599        icon_size: ui::IconSize,
 6600        display_row: DisplayRow,
 6601        is_active: bool,
 6602        cx: &mut Context<Self>,
 6603    ) -> AnyElement {
 6604        let show_tooltip = !self.context_menu_visible();
 6605        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6606            .icon_size(icon_size)
 6607            .shape(ui::IconButtonShape::Square)
 6608            .icon_color(ui::Color::Hidden)
 6609            .toggle_state(is_active)
 6610            .when(show_tooltip, |this| {
 6611                this.tooltip({
 6612                    let focus_handle = self.focus_handle.clone();
 6613                    move |window, cx| {
 6614                        Tooltip::for_action_in(
 6615                            "Toggle Code Actions",
 6616                            &ToggleCodeActions {
 6617                                deployed_from: None,
 6618                                quick_launch: false,
 6619                            },
 6620                            &focus_handle,
 6621                            window,
 6622                            cx,
 6623                        )
 6624                    }
 6625                })
 6626            })
 6627            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6628                window.focus(&editor.focus_handle(cx));
 6629                editor.toggle_code_actions(
 6630                    &crate::actions::ToggleCodeActions {
 6631                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6632                            display_row,
 6633                        )),
 6634                        quick_launch: false,
 6635                    },
 6636                    window,
 6637                    cx,
 6638                );
 6639            }))
 6640            .into_any_element()
 6641    }
 6642
 6643    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6644        &self.context_menu
 6645    }
 6646
 6647    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6648        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6649            cx.background_executor()
 6650                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6651                .await;
 6652
 6653            let (start_buffer, start, _, end, newest_selection) = this
 6654                .update(cx, |this, cx| {
 6655                    let newest_selection = this.selections.newest_anchor().clone();
 6656                    if newest_selection.head().diff_base_anchor.is_some() {
 6657                        return None;
 6658                    }
 6659                    let display_snapshot = this.display_snapshot(cx);
 6660                    let newest_selection_adjusted =
 6661                        this.selections.newest_adjusted(&display_snapshot);
 6662                    let buffer = this.buffer.read(cx);
 6663
 6664                    let (start_buffer, start) =
 6665                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6666                    let (end_buffer, end) =
 6667                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6668
 6669                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6670                })?
 6671                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6672                .context(
 6673                    "Expected selection to lie in a single buffer when refreshing code actions",
 6674                )?;
 6675            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6676                let providers = this.code_action_providers.clone();
 6677                let tasks = this
 6678                    .code_action_providers
 6679                    .iter()
 6680                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6681                    .collect::<Vec<_>>();
 6682                (providers, tasks)
 6683            })?;
 6684
 6685            let mut actions = Vec::new();
 6686            for (provider, provider_actions) in
 6687                providers.into_iter().zip(future::join_all(tasks).await)
 6688            {
 6689                if let Some(provider_actions) = provider_actions.log_err() {
 6690                    actions.extend(provider_actions.into_iter().map(|action| {
 6691                        AvailableCodeAction {
 6692                            excerpt_id: newest_selection.start.excerpt_id,
 6693                            action,
 6694                            provider: provider.clone(),
 6695                        }
 6696                    }));
 6697                }
 6698            }
 6699
 6700            this.update(cx, |this, cx| {
 6701                this.available_code_actions = if actions.is_empty() {
 6702                    None
 6703                } else {
 6704                    Some((
 6705                        Location {
 6706                            buffer: start_buffer,
 6707                            range: start..end,
 6708                        },
 6709                        actions.into(),
 6710                    ))
 6711                };
 6712                cx.notify();
 6713            })
 6714        }));
 6715    }
 6716
 6717    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6718        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6719            self.show_git_blame_inline = false;
 6720
 6721            self.show_git_blame_inline_delay_task =
 6722                Some(cx.spawn_in(window, async move |this, cx| {
 6723                    cx.background_executor().timer(delay).await;
 6724
 6725                    this.update(cx, |this, cx| {
 6726                        this.show_git_blame_inline = true;
 6727                        cx.notify();
 6728                    })
 6729                    .log_err();
 6730                }));
 6731        }
 6732    }
 6733
 6734    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6735        let snapshot = self.snapshot(window, cx);
 6736        let cursor = self
 6737            .selections
 6738            .newest::<Point>(&snapshot.display_snapshot)
 6739            .head();
 6740        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6741        else {
 6742            return;
 6743        };
 6744
 6745        let Some(blame) = self.blame.as_ref() else {
 6746            return;
 6747        };
 6748
 6749        let row_info = RowInfo {
 6750            buffer_id: Some(buffer.remote_id()),
 6751            buffer_row: Some(point.row),
 6752            ..Default::default()
 6753        };
 6754        let Some((buffer, blame_entry)) = blame
 6755            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6756            .flatten()
 6757        else {
 6758            return;
 6759        };
 6760
 6761        let anchor = self.selections.newest_anchor().head();
 6762        let position = self.to_pixel_point(anchor, &snapshot, window);
 6763        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6764            self.show_blame_popover(
 6765                buffer,
 6766                &blame_entry,
 6767                position + last_bounds.origin,
 6768                true,
 6769                cx,
 6770            );
 6771        };
 6772    }
 6773
 6774    fn show_blame_popover(
 6775        &mut self,
 6776        buffer: BufferId,
 6777        blame_entry: &BlameEntry,
 6778        position: gpui::Point<Pixels>,
 6779        ignore_timeout: bool,
 6780        cx: &mut Context<Self>,
 6781    ) {
 6782        if let Some(state) = &mut self.inline_blame_popover {
 6783            state.hide_task.take();
 6784        } else {
 6785            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6786            let blame_entry = blame_entry.clone();
 6787            let show_task = cx.spawn(async move |editor, cx| {
 6788                if !ignore_timeout {
 6789                    cx.background_executor()
 6790                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6791                        .await;
 6792                }
 6793                editor
 6794                    .update(cx, |editor, cx| {
 6795                        editor.inline_blame_popover_show_task.take();
 6796                        let Some(blame) = editor.blame.as_ref() else {
 6797                            return;
 6798                        };
 6799                        let blame = blame.read(cx);
 6800                        let details = blame.details_for_entry(buffer, &blame_entry);
 6801                        let markdown = cx.new(|cx| {
 6802                            Markdown::new(
 6803                                details
 6804                                    .as_ref()
 6805                                    .map(|message| message.message.clone())
 6806                                    .unwrap_or_default(),
 6807                                None,
 6808                                None,
 6809                                cx,
 6810                            )
 6811                        });
 6812                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6813                            position,
 6814                            hide_task: None,
 6815                            popover_bounds: None,
 6816                            popover_state: InlineBlamePopoverState {
 6817                                scroll_handle: ScrollHandle::new(),
 6818                                commit_message: details,
 6819                                markdown,
 6820                            },
 6821                            keyboard_grace: ignore_timeout,
 6822                        });
 6823                        cx.notify();
 6824                    })
 6825                    .ok();
 6826            });
 6827            self.inline_blame_popover_show_task = Some(show_task);
 6828        }
 6829    }
 6830
 6831    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6832        self.inline_blame_popover_show_task.take();
 6833        if let Some(state) = &mut self.inline_blame_popover {
 6834            let hide_task = cx.spawn(async move |editor, cx| {
 6835                cx.background_executor()
 6836                    .timer(std::time::Duration::from_millis(100))
 6837                    .await;
 6838                editor
 6839                    .update(cx, |editor, cx| {
 6840                        editor.inline_blame_popover.take();
 6841                        cx.notify();
 6842                    })
 6843                    .ok();
 6844            });
 6845            state.hide_task = Some(hide_task);
 6846        }
 6847    }
 6848
 6849    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6850        if self.pending_rename.is_some() {
 6851            return None;
 6852        }
 6853
 6854        let provider = self.semantics_provider.clone()?;
 6855        let buffer = self.buffer.read(cx);
 6856        let newest_selection = self.selections.newest_anchor().clone();
 6857        let cursor_position = newest_selection.head();
 6858        let (cursor_buffer, cursor_buffer_position) =
 6859            buffer.text_anchor_for_position(cursor_position, cx)?;
 6860        let (tail_buffer, tail_buffer_position) =
 6861            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6862        if cursor_buffer != tail_buffer {
 6863            return None;
 6864        }
 6865
 6866        let snapshot = cursor_buffer.read(cx).snapshot();
 6867        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6868        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6869        if start_word_range != end_word_range {
 6870            self.document_highlights_task.take();
 6871            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6872            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6873            return None;
 6874        }
 6875
 6876        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6877        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6878            cx.background_executor()
 6879                .timer(Duration::from_millis(debounce))
 6880                .await;
 6881
 6882            let highlights = if let Some(highlights) = cx
 6883                .update(|cx| {
 6884                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6885                })
 6886                .ok()
 6887                .flatten()
 6888            {
 6889                highlights.await.log_err()
 6890            } else {
 6891                None
 6892            };
 6893
 6894            if let Some(highlights) = highlights {
 6895                this.update(cx, |this, cx| {
 6896                    if this.pending_rename.is_some() {
 6897                        return;
 6898                    }
 6899
 6900                    let buffer = this.buffer.read(cx);
 6901                    if buffer
 6902                        .text_anchor_for_position(cursor_position, cx)
 6903                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6904                    {
 6905                        return;
 6906                    }
 6907
 6908                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6909                    let mut write_ranges = Vec::new();
 6910                    let mut read_ranges = Vec::new();
 6911                    for highlight in highlights {
 6912                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6913                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6914                        {
 6915                            let start = highlight
 6916                                .range
 6917                                .start
 6918                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6919                            let end = highlight
 6920                                .range
 6921                                .end
 6922                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6923                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6924                                continue;
 6925                            }
 6926
 6927                            let range =
 6928                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6929                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6930                                write_ranges.push(range);
 6931                            } else {
 6932                                read_ranges.push(range);
 6933                            }
 6934                        }
 6935                    }
 6936
 6937                    this.highlight_background::<DocumentHighlightRead>(
 6938                        &read_ranges,
 6939                        |theme| theme.colors().editor_document_highlight_read_background,
 6940                        cx,
 6941                    );
 6942                    this.highlight_background::<DocumentHighlightWrite>(
 6943                        &write_ranges,
 6944                        |theme| theme.colors().editor_document_highlight_write_background,
 6945                        cx,
 6946                    );
 6947                    cx.notify();
 6948                })
 6949                .log_err();
 6950            }
 6951        }));
 6952        None
 6953    }
 6954
 6955    fn prepare_highlight_query_from_selection(
 6956        &mut self,
 6957        cx: &mut Context<Editor>,
 6958    ) -> Option<(String, Range<Anchor>)> {
 6959        if matches!(self.mode, EditorMode::SingleLine) {
 6960            return None;
 6961        }
 6962        if !EditorSettings::get_global(cx).selection_highlight {
 6963            return None;
 6964        }
 6965        if self.selections.count() != 1 || self.selections.line_mode() {
 6966            return None;
 6967        }
 6968        let selection = self.selections.newest_anchor();
 6969        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6970        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6971            ..selection.end.to_point(&multi_buffer_snapshot);
 6972        // If the selection spans multiple rows OR it is empty
 6973        if selection_point_range.start.row != selection_point_range.end.row
 6974            || selection_point_range.start.column == selection_point_range.end.column
 6975        {
 6976            return None;
 6977        }
 6978
 6979        let query = multi_buffer_snapshot
 6980            .text_for_range(selection.range())
 6981            .collect::<String>();
 6982        if query.trim().is_empty() {
 6983            return None;
 6984        }
 6985        Some((query, selection.range()))
 6986    }
 6987
 6988    fn update_selection_occurrence_highlights(
 6989        &mut self,
 6990        query_text: String,
 6991        query_range: Range<Anchor>,
 6992        multi_buffer_range_to_query: Range<Point>,
 6993        use_debounce: bool,
 6994        window: &mut Window,
 6995        cx: &mut Context<Editor>,
 6996    ) -> Task<()> {
 6997        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6998        cx.spawn_in(window, async move |editor, cx| {
 6999            if use_debounce {
 7000                cx.background_executor()
 7001                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7002                    .await;
 7003            }
 7004            let match_task = cx.background_spawn(async move {
 7005                let buffer_ranges = multi_buffer_snapshot
 7006                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7007                    .into_iter()
 7008                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7009                let mut match_ranges = Vec::new();
 7010                let Ok(regex) = project::search::SearchQuery::text(
 7011                    query_text.clone(),
 7012                    false,
 7013                    false,
 7014                    false,
 7015                    Default::default(),
 7016                    Default::default(),
 7017                    false,
 7018                    None,
 7019                ) else {
 7020                    return Vec::default();
 7021                };
 7022                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7023                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7024                    match_ranges.extend(
 7025                        regex
 7026                            .search(buffer_snapshot, Some(search_range.clone()))
 7027                            .await
 7028                            .into_iter()
 7029                            .filter_map(|match_range| {
 7030                                let match_start = buffer_snapshot
 7031                                    .anchor_after(search_range.start + match_range.start);
 7032                                let match_end = buffer_snapshot
 7033                                    .anchor_before(search_range.start + match_range.end);
 7034                                let match_anchor_range = Anchor::range_in_buffer(
 7035                                    excerpt_id,
 7036                                    buffer_snapshot.remote_id(),
 7037                                    match_start..match_end,
 7038                                );
 7039                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7040                            }),
 7041                    );
 7042                }
 7043                match_ranges
 7044            });
 7045            let match_ranges = match_task.await;
 7046            editor
 7047                .update_in(cx, |editor, _, cx| {
 7048                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7049                    if !match_ranges.is_empty() {
 7050                        editor.highlight_background::<SelectedTextHighlight>(
 7051                            &match_ranges,
 7052                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7053                            cx,
 7054                        )
 7055                    }
 7056                })
 7057                .log_err();
 7058        })
 7059    }
 7060
 7061    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7062        struct NewlineFold;
 7063        let type_id = std::any::TypeId::of::<NewlineFold>();
 7064        if !self.mode.is_single_line() {
 7065            return;
 7066        }
 7067        let snapshot = self.snapshot(window, cx);
 7068        if snapshot.buffer_snapshot().max_point().row == 0 {
 7069            return;
 7070        }
 7071        let task = cx.background_spawn(async move {
 7072            let new_newlines = snapshot
 7073                .buffer_chars_at(0)
 7074                .filter_map(|(c, i)| {
 7075                    if c == '\n' {
 7076                        Some(
 7077                            snapshot.buffer_snapshot().anchor_after(i)
 7078                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7079                        )
 7080                    } else {
 7081                        None
 7082                    }
 7083                })
 7084                .collect::<Vec<_>>();
 7085            let existing_newlines = snapshot
 7086                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7087                .filter_map(|fold| {
 7088                    if fold.placeholder.type_tag == Some(type_id) {
 7089                        Some(fold.range.start..fold.range.end)
 7090                    } else {
 7091                        None
 7092                    }
 7093                })
 7094                .collect::<Vec<_>>();
 7095
 7096            (new_newlines, existing_newlines)
 7097        });
 7098        self.folding_newlines = cx.spawn(async move |this, cx| {
 7099            let (new_newlines, existing_newlines) = task.await;
 7100            if new_newlines == existing_newlines {
 7101                return;
 7102            }
 7103            let placeholder = FoldPlaceholder {
 7104                render: Arc::new(move |_, _, cx| {
 7105                    div()
 7106                        .bg(cx.theme().status().hint_background)
 7107                        .border_b_1()
 7108                        .size_full()
 7109                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7110                        .border_color(cx.theme().status().hint)
 7111                        .child("\\n")
 7112                        .into_any()
 7113                }),
 7114                constrain_width: false,
 7115                merge_adjacent: false,
 7116                type_tag: Some(type_id),
 7117            };
 7118            let creases = new_newlines
 7119                .into_iter()
 7120                .map(|range| Crease::simple(range, placeholder.clone()))
 7121                .collect();
 7122            this.update(cx, |this, cx| {
 7123                this.display_map.update(cx, |display_map, cx| {
 7124                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7125                    display_map.fold(creases, cx);
 7126                });
 7127            })
 7128            .ok();
 7129        });
 7130    }
 7131
 7132    fn refresh_selected_text_highlights(
 7133        &mut self,
 7134        on_buffer_edit: bool,
 7135        window: &mut Window,
 7136        cx: &mut Context<Editor>,
 7137    ) {
 7138        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7139        else {
 7140            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7141            self.quick_selection_highlight_task.take();
 7142            self.debounced_selection_highlight_task.take();
 7143            return;
 7144        };
 7145        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7146        if on_buffer_edit
 7147            || self
 7148                .quick_selection_highlight_task
 7149                .as_ref()
 7150                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7151        {
 7152            let multi_buffer_visible_start = self
 7153                .scroll_manager
 7154                .anchor()
 7155                .anchor
 7156                .to_point(&multi_buffer_snapshot);
 7157            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7158                multi_buffer_visible_start
 7159                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7160                Bias::Left,
 7161            );
 7162            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7163            self.quick_selection_highlight_task = Some((
 7164                query_range.clone(),
 7165                self.update_selection_occurrence_highlights(
 7166                    query_text.clone(),
 7167                    query_range.clone(),
 7168                    multi_buffer_visible_range,
 7169                    false,
 7170                    window,
 7171                    cx,
 7172                ),
 7173            ));
 7174        }
 7175        if on_buffer_edit
 7176            || self
 7177                .debounced_selection_highlight_task
 7178                .as_ref()
 7179                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7180        {
 7181            let multi_buffer_start = multi_buffer_snapshot
 7182                .anchor_before(0)
 7183                .to_point(&multi_buffer_snapshot);
 7184            let multi_buffer_end = multi_buffer_snapshot
 7185                .anchor_after(multi_buffer_snapshot.len())
 7186                .to_point(&multi_buffer_snapshot);
 7187            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7188            self.debounced_selection_highlight_task = Some((
 7189                query_range.clone(),
 7190                self.update_selection_occurrence_highlights(
 7191                    query_text,
 7192                    query_range,
 7193                    multi_buffer_full_range,
 7194                    true,
 7195                    window,
 7196                    cx,
 7197                ),
 7198            ));
 7199        }
 7200    }
 7201
 7202    pub fn refresh_edit_prediction(
 7203        &mut self,
 7204        debounce: bool,
 7205        user_requested: bool,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) -> Option<()> {
 7209        if DisableAiSettings::get_global(cx).disable_ai {
 7210            return None;
 7211        }
 7212
 7213        let provider = self.edit_prediction_provider()?;
 7214        let cursor = self.selections.newest_anchor().head();
 7215        let (buffer, cursor_buffer_position) =
 7216            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7217
 7218        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7219            self.discard_edit_prediction(false, cx);
 7220            return None;
 7221        }
 7222
 7223        self.update_visible_edit_prediction(window, cx);
 7224
 7225        if !user_requested
 7226            && (!self.should_show_edit_predictions()
 7227                || !self.is_focused(window)
 7228                || buffer.read(cx).is_empty())
 7229        {
 7230            self.discard_edit_prediction(false, cx);
 7231            return None;
 7232        }
 7233
 7234        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7235        Some(())
 7236    }
 7237
 7238    fn show_edit_predictions_in_menu(&self) -> bool {
 7239        match self.edit_prediction_settings {
 7240            EditPredictionSettings::Disabled => false,
 7241            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7242        }
 7243    }
 7244
 7245    pub fn edit_predictions_enabled(&self) -> bool {
 7246        match self.edit_prediction_settings {
 7247            EditPredictionSettings::Disabled => false,
 7248            EditPredictionSettings::Enabled { .. } => true,
 7249        }
 7250    }
 7251
 7252    fn edit_prediction_requires_modifier(&self) -> bool {
 7253        match self.edit_prediction_settings {
 7254            EditPredictionSettings::Disabled => false,
 7255            EditPredictionSettings::Enabled {
 7256                preview_requires_modifier,
 7257                ..
 7258            } => preview_requires_modifier,
 7259        }
 7260    }
 7261
 7262    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7263        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7264            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7265            self.discard_edit_prediction(false, cx);
 7266        } else {
 7267            let selection = self.selections.newest_anchor();
 7268            let cursor = selection.head();
 7269
 7270            if let Some((buffer, cursor_buffer_position)) =
 7271                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7272            {
 7273                self.edit_prediction_settings =
 7274                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7275            }
 7276        }
 7277    }
 7278
 7279    fn edit_prediction_settings_at_position(
 7280        &self,
 7281        buffer: &Entity<Buffer>,
 7282        buffer_position: language::Anchor,
 7283        cx: &App,
 7284    ) -> EditPredictionSettings {
 7285        if !self.mode.is_full()
 7286            || !self.show_edit_predictions_override.unwrap_or(true)
 7287            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7288        {
 7289            return EditPredictionSettings::Disabled;
 7290        }
 7291
 7292        let buffer = buffer.read(cx);
 7293
 7294        let file = buffer.file();
 7295
 7296        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7297            return EditPredictionSettings::Disabled;
 7298        };
 7299
 7300        let by_provider = matches!(
 7301            self.menu_edit_predictions_policy,
 7302            MenuEditPredictionsPolicy::ByProvider
 7303        );
 7304
 7305        let show_in_menu = by_provider
 7306            && self
 7307                .edit_prediction_provider
 7308                .as_ref()
 7309                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7310
 7311        let preview_requires_modifier =
 7312            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7313
 7314        EditPredictionSettings::Enabled {
 7315            show_in_menu,
 7316            preview_requires_modifier,
 7317        }
 7318    }
 7319
 7320    fn should_show_edit_predictions(&self) -> bool {
 7321        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7322    }
 7323
 7324    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7325        matches!(
 7326            self.edit_prediction_preview,
 7327            EditPredictionPreview::Active { .. }
 7328        )
 7329    }
 7330
 7331    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7332        let cursor = self.selections.newest_anchor().head();
 7333        if let Some((buffer, cursor_position)) =
 7334            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7335        {
 7336            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7337        } else {
 7338            false
 7339        }
 7340    }
 7341
 7342    pub fn supports_minimap(&self, cx: &App) -> bool {
 7343        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7344    }
 7345
 7346    fn edit_predictions_enabled_in_buffer(
 7347        &self,
 7348        buffer: &Entity<Buffer>,
 7349        buffer_position: language::Anchor,
 7350        cx: &App,
 7351    ) -> bool {
 7352        maybe!({
 7353            if self.read_only(cx) {
 7354                return Some(false);
 7355            }
 7356            let provider = self.edit_prediction_provider()?;
 7357            if !provider.is_enabled(buffer, buffer_position, cx) {
 7358                return Some(false);
 7359            }
 7360            let buffer = buffer.read(cx);
 7361            let Some(file) = buffer.file() else {
 7362                return Some(true);
 7363            };
 7364            let settings = all_language_settings(Some(file), cx);
 7365            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7366        })
 7367        .unwrap_or(false)
 7368    }
 7369
 7370    fn cycle_edit_prediction(
 7371        &mut self,
 7372        direction: Direction,
 7373        window: &mut Window,
 7374        cx: &mut Context<Self>,
 7375    ) -> Option<()> {
 7376        let provider = self.edit_prediction_provider()?;
 7377        let cursor = self.selections.newest_anchor().head();
 7378        let (buffer, cursor_buffer_position) =
 7379            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7380        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7381            return None;
 7382        }
 7383
 7384        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7385        self.update_visible_edit_prediction(window, cx);
 7386
 7387        Some(())
 7388    }
 7389
 7390    pub fn show_edit_prediction(
 7391        &mut self,
 7392        _: &ShowEditPrediction,
 7393        window: &mut Window,
 7394        cx: &mut Context<Self>,
 7395    ) {
 7396        if !self.has_active_edit_prediction() {
 7397            self.refresh_edit_prediction(false, true, window, cx);
 7398            return;
 7399        }
 7400
 7401        self.update_visible_edit_prediction(window, cx);
 7402    }
 7403
 7404    pub fn display_cursor_names(
 7405        &mut self,
 7406        _: &DisplayCursorNames,
 7407        window: &mut Window,
 7408        cx: &mut Context<Self>,
 7409    ) {
 7410        self.show_cursor_names(window, cx);
 7411    }
 7412
 7413    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7414        self.show_cursor_names = true;
 7415        cx.notify();
 7416        cx.spawn_in(window, async move |this, cx| {
 7417            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7418            this.update(cx, |this, cx| {
 7419                this.show_cursor_names = false;
 7420                cx.notify()
 7421            })
 7422            .ok()
 7423        })
 7424        .detach();
 7425    }
 7426
 7427    pub fn next_edit_prediction(
 7428        &mut self,
 7429        _: &NextEditPrediction,
 7430        window: &mut Window,
 7431        cx: &mut Context<Self>,
 7432    ) {
 7433        if self.has_active_edit_prediction() {
 7434            self.cycle_edit_prediction(Direction::Next, window, cx);
 7435        } else {
 7436            let is_copilot_disabled = self
 7437                .refresh_edit_prediction(false, true, window, cx)
 7438                .is_none();
 7439            if is_copilot_disabled {
 7440                cx.propagate();
 7441            }
 7442        }
 7443    }
 7444
 7445    pub fn previous_edit_prediction(
 7446        &mut self,
 7447        _: &PreviousEditPrediction,
 7448        window: &mut Window,
 7449        cx: &mut Context<Self>,
 7450    ) {
 7451        if self.has_active_edit_prediction() {
 7452            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7453        } else {
 7454            let is_copilot_disabled = self
 7455                .refresh_edit_prediction(false, true, window, cx)
 7456                .is_none();
 7457            if is_copilot_disabled {
 7458                cx.propagate();
 7459            }
 7460        }
 7461    }
 7462
 7463    pub fn accept_edit_prediction(
 7464        &mut self,
 7465        _: &AcceptEditPrediction,
 7466        window: &mut Window,
 7467        cx: &mut Context<Self>,
 7468    ) {
 7469        if self.show_edit_predictions_in_menu() {
 7470            self.hide_context_menu(window, cx);
 7471        }
 7472
 7473        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7474            return;
 7475        };
 7476
 7477        match &active_edit_prediction.completion {
 7478            EditPrediction::MoveWithin { target, .. } => {
 7479                let target = *target;
 7480
 7481                if let Some(position_map) = &self.last_position_map {
 7482                    if position_map
 7483                        .visible_row_range
 7484                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7485                        || !self.edit_prediction_requires_modifier()
 7486                    {
 7487                        self.unfold_ranges(&[target..target], true, false, cx);
 7488                        // Note that this is also done in vim's handler of the Tab action.
 7489                        self.change_selections(
 7490                            SelectionEffects::scroll(Autoscroll::newest()),
 7491                            window,
 7492                            cx,
 7493                            |selections| {
 7494                                selections.select_anchor_ranges([target..target]);
 7495                            },
 7496                        );
 7497                        self.clear_row_highlights::<EditPredictionPreview>();
 7498
 7499                        self.edit_prediction_preview
 7500                            .set_previous_scroll_position(None);
 7501                    } else {
 7502                        self.edit_prediction_preview
 7503                            .set_previous_scroll_position(Some(
 7504                                position_map.snapshot.scroll_anchor,
 7505                            ));
 7506
 7507                        self.highlight_rows::<EditPredictionPreview>(
 7508                            target..target,
 7509                            cx.theme().colors().editor_highlighted_line_background,
 7510                            RowHighlightOptions {
 7511                                autoscroll: true,
 7512                                ..Default::default()
 7513                            },
 7514                            cx,
 7515                        );
 7516                        self.request_autoscroll(Autoscroll::fit(), cx);
 7517                    }
 7518                }
 7519            }
 7520            EditPrediction::MoveOutside { snapshot, target } => {
 7521                if let Some(workspace) = self.workspace() {
 7522                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7523                        .detach_and_log_err(cx);
 7524                }
 7525            }
 7526            EditPrediction::Edit { edits, .. } => {
 7527                self.report_edit_prediction_event(
 7528                    active_edit_prediction.completion_id.clone(),
 7529                    true,
 7530                    cx,
 7531                );
 7532
 7533                if let Some(provider) = self.edit_prediction_provider() {
 7534                    provider.accept(cx);
 7535                }
 7536
 7537                // Store the transaction ID and selections before applying the edit
 7538                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7539
 7540                let snapshot = self.buffer.read(cx).snapshot(cx);
 7541                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7542
 7543                self.buffer.update(cx, |buffer, cx| {
 7544                    buffer.edit(edits.iter().cloned(), None, cx)
 7545                });
 7546
 7547                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7548                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7549                });
 7550
 7551                let selections = self.selections.disjoint_anchors_arc();
 7552                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7553                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7554                    if has_new_transaction {
 7555                        self.selection_history
 7556                            .insert_transaction(transaction_id_now, selections);
 7557                    }
 7558                }
 7559
 7560                self.update_visible_edit_prediction(window, cx);
 7561                if self.active_edit_prediction.is_none() {
 7562                    self.refresh_edit_prediction(true, true, window, cx);
 7563                }
 7564
 7565                cx.notify();
 7566            }
 7567        }
 7568
 7569        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7570    }
 7571
 7572    pub fn accept_partial_edit_prediction(
 7573        &mut self,
 7574        _: &AcceptPartialEditPrediction,
 7575        window: &mut Window,
 7576        cx: &mut Context<Self>,
 7577    ) {
 7578        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7579            return;
 7580        };
 7581        if self.selections.count() != 1 {
 7582            return;
 7583        }
 7584
 7585        match &active_edit_prediction.completion {
 7586            EditPrediction::MoveWithin { target, .. } => {
 7587                let target = *target;
 7588                self.change_selections(
 7589                    SelectionEffects::scroll(Autoscroll::newest()),
 7590                    window,
 7591                    cx,
 7592                    |selections| {
 7593                        selections.select_anchor_ranges([target..target]);
 7594                    },
 7595                );
 7596            }
 7597            EditPrediction::MoveOutside { snapshot, target } => {
 7598                if let Some(workspace) = self.workspace() {
 7599                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7600                        .detach_and_log_err(cx);
 7601                }
 7602            }
 7603            EditPrediction::Edit { edits, .. } => {
 7604                self.report_edit_prediction_event(
 7605                    active_edit_prediction.completion_id.clone(),
 7606                    true,
 7607                    cx,
 7608                );
 7609
 7610                // Find an insertion that starts at the cursor position.
 7611                let snapshot = self.buffer.read(cx).snapshot(cx);
 7612                let cursor_offset = self
 7613                    .selections
 7614                    .newest::<usize>(&self.display_snapshot(cx))
 7615                    .head();
 7616                let insertion = edits.iter().find_map(|(range, text)| {
 7617                    let range = range.to_offset(&snapshot);
 7618                    if range.is_empty() && range.start == cursor_offset {
 7619                        Some(text)
 7620                    } else {
 7621                        None
 7622                    }
 7623                });
 7624
 7625                if let Some(text) = insertion {
 7626                    let mut partial_completion = text
 7627                        .chars()
 7628                        .by_ref()
 7629                        .take_while(|c| c.is_alphabetic())
 7630                        .collect::<String>();
 7631                    if partial_completion.is_empty() {
 7632                        partial_completion = text
 7633                            .chars()
 7634                            .by_ref()
 7635                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7636                            .collect::<String>();
 7637                    }
 7638
 7639                    cx.emit(EditorEvent::InputHandled {
 7640                        utf16_range_to_replace: None,
 7641                        text: partial_completion.clone().into(),
 7642                    });
 7643
 7644                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7645
 7646                    self.refresh_edit_prediction(true, true, window, cx);
 7647                    cx.notify();
 7648                } else {
 7649                    self.accept_edit_prediction(&Default::default(), window, cx);
 7650                }
 7651            }
 7652        }
 7653    }
 7654
 7655    fn discard_edit_prediction(
 7656        &mut self,
 7657        should_report_edit_prediction_event: bool,
 7658        cx: &mut Context<Self>,
 7659    ) -> bool {
 7660        if should_report_edit_prediction_event {
 7661            let completion_id = self
 7662                .active_edit_prediction
 7663                .as_ref()
 7664                .and_then(|active_completion| active_completion.completion_id.clone());
 7665
 7666            self.report_edit_prediction_event(completion_id, false, cx);
 7667        }
 7668
 7669        if let Some(provider) = self.edit_prediction_provider() {
 7670            provider.discard(cx);
 7671        }
 7672
 7673        self.take_active_edit_prediction(cx)
 7674    }
 7675
 7676    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7677        let Some(provider) = self.edit_prediction_provider() else {
 7678            return;
 7679        };
 7680
 7681        let Some((_, buffer, _)) = self
 7682            .buffer
 7683            .read(cx)
 7684            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7685        else {
 7686            return;
 7687        };
 7688
 7689        let extension = buffer
 7690            .read(cx)
 7691            .file()
 7692            .and_then(|file| Some(file.path().extension()?.to_string()));
 7693
 7694        let event_type = match accepted {
 7695            true => "Edit Prediction Accepted",
 7696            false => "Edit Prediction Discarded",
 7697        };
 7698        telemetry::event!(
 7699            event_type,
 7700            provider = provider.name(),
 7701            prediction_id = id,
 7702            suggestion_accepted = accepted,
 7703            file_extension = extension,
 7704        );
 7705    }
 7706
 7707    fn open_editor_at_anchor(
 7708        snapshot: &language::BufferSnapshot,
 7709        target: language::Anchor,
 7710        workspace: &Entity<Workspace>,
 7711        window: &mut Window,
 7712        cx: &mut App,
 7713    ) -> Task<Result<()>> {
 7714        workspace.update(cx, |workspace, cx| {
 7715            let path = snapshot.file().map(|file| file.full_path(cx));
 7716            let Some(path) =
 7717                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7718            else {
 7719                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7720            };
 7721            let target = text::ToPoint::to_point(&target, snapshot);
 7722            let item = workspace.open_path(path, None, true, window, cx);
 7723            window.spawn(cx, async move |cx| {
 7724                let Some(editor) = item.await?.downcast::<Editor>() else {
 7725                    return Ok(());
 7726                };
 7727                editor
 7728                    .update_in(cx, |editor, window, cx| {
 7729                        editor.go_to_singleton_buffer_point(target, window, cx);
 7730                    })
 7731                    .ok();
 7732                anyhow::Ok(())
 7733            })
 7734        })
 7735    }
 7736
 7737    pub fn has_active_edit_prediction(&self) -> bool {
 7738        self.active_edit_prediction.is_some()
 7739    }
 7740
 7741    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7742        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7743            return false;
 7744        };
 7745
 7746        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7747        self.clear_highlights::<EditPredictionHighlight>(cx);
 7748        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7749        true
 7750    }
 7751
 7752    /// Returns true when we're displaying the edit prediction popover below the cursor
 7753    /// like we are not previewing and the LSP autocomplete menu is visible
 7754    /// or we are in `when_holding_modifier` mode.
 7755    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7756        if self.edit_prediction_preview_is_active()
 7757            || !self.show_edit_predictions_in_menu()
 7758            || !self.edit_predictions_enabled()
 7759        {
 7760            return false;
 7761        }
 7762
 7763        if self.has_visible_completions_menu() {
 7764            return true;
 7765        }
 7766
 7767        has_completion && self.edit_prediction_requires_modifier()
 7768    }
 7769
 7770    fn handle_modifiers_changed(
 7771        &mut self,
 7772        modifiers: Modifiers,
 7773        position_map: &PositionMap,
 7774        window: &mut Window,
 7775        cx: &mut Context<Self>,
 7776    ) {
 7777        if self.show_edit_predictions_in_menu() {
 7778            self.update_edit_prediction_preview(&modifiers, window, cx);
 7779        }
 7780
 7781        self.update_selection_mode(&modifiers, position_map, window, cx);
 7782
 7783        let mouse_position = window.mouse_position();
 7784        if !position_map.text_hitbox.is_hovered(window) {
 7785            return;
 7786        }
 7787
 7788        self.update_hovered_link(
 7789            position_map.point_for_position(mouse_position),
 7790            &position_map.snapshot,
 7791            modifiers,
 7792            window,
 7793            cx,
 7794        )
 7795    }
 7796
 7797    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7798        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7799        if invert {
 7800            match multi_cursor_setting {
 7801                MultiCursorModifier::Alt => modifiers.alt,
 7802                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7803            }
 7804        } else {
 7805            match multi_cursor_setting {
 7806                MultiCursorModifier::Alt => modifiers.secondary(),
 7807                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7808            }
 7809        }
 7810    }
 7811
 7812    fn columnar_selection_mode(
 7813        modifiers: &Modifiers,
 7814        cx: &mut Context<Self>,
 7815    ) -> Option<ColumnarMode> {
 7816        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7817            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7818                Some(ColumnarMode::FromMouse)
 7819            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7820                Some(ColumnarMode::FromSelection)
 7821            } else {
 7822                None
 7823            }
 7824        } else {
 7825            None
 7826        }
 7827    }
 7828
 7829    fn update_selection_mode(
 7830        &mut self,
 7831        modifiers: &Modifiers,
 7832        position_map: &PositionMap,
 7833        window: &mut Window,
 7834        cx: &mut Context<Self>,
 7835    ) {
 7836        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7837            return;
 7838        };
 7839        if self.selections.pending_anchor().is_none() {
 7840            return;
 7841        }
 7842
 7843        let mouse_position = window.mouse_position();
 7844        let point_for_position = position_map.point_for_position(mouse_position);
 7845        let position = point_for_position.previous_valid;
 7846
 7847        self.select(
 7848            SelectPhase::BeginColumnar {
 7849                position,
 7850                reset: false,
 7851                mode,
 7852                goal_column: point_for_position.exact_unclipped.column(),
 7853            },
 7854            window,
 7855            cx,
 7856        );
 7857    }
 7858
 7859    fn update_edit_prediction_preview(
 7860        &mut self,
 7861        modifiers: &Modifiers,
 7862        window: &mut Window,
 7863        cx: &mut Context<Self>,
 7864    ) {
 7865        let mut modifiers_held = false;
 7866        if let Some(accept_keystroke) = self
 7867            .accept_edit_prediction_keybind(false, window, cx)
 7868            .keystroke()
 7869        {
 7870            modifiers_held = modifiers_held
 7871                || (accept_keystroke.modifiers() == modifiers
 7872                    && accept_keystroke.modifiers().modified());
 7873        };
 7874        if let Some(accept_partial_keystroke) = self
 7875            .accept_edit_prediction_keybind(true, window, cx)
 7876            .keystroke()
 7877        {
 7878            modifiers_held = modifiers_held
 7879                || (accept_partial_keystroke.modifiers() == modifiers
 7880                    && accept_partial_keystroke.modifiers().modified());
 7881        }
 7882
 7883        if modifiers_held {
 7884            if matches!(
 7885                self.edit_prediction_preview,
 7886                EditPredictionPreview::Inactive { .. }
 7887            ) {
 7888                self.edit_prediction_preview = EditPredictionPreview::Active {
 7889                    previous_scroll_position: None,
 7890                    since: Instant::now(),
 7891                };
 7892
 7893                self.update_visible_edit_prediction(window, cx);
 7894                cx.notify();
 7895            }
 7896        } else if let EditPredictionPreview::Active {
 7897            previous_scroll_position,
 7898            since,
 7899        } = self.edit_prediction_preview
 7900        {
 7901            if let (Some(previous_scroll_position), Some(position_map)) =
 7902                (previous_scroll_position, self.last_position_map.as_ref())
 7903            {
 7904                self.set_scroll_position(
 7905                    previous_scroll_position
 7906                        .scroll_position(&position_map.snapshot.display_snapshot),
 7907                    window,
 7908                    cx,
 7909                );
 7910            }
 7911
 7912            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7913                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7914            };
 7915            self.clear_row_highlights::<EditPredictionPreview>();
 7916            self.update_visible_edit_prediction(window, cx);
 7917            cx.notify();
 7918        }
 7919    }
 7920
 7921    fn update_visible_edit_prediction(
 7922        &mut self,
 7923        _window: &mut Window,
 7924        cx: &mut Context<Self>,
 7925    ) -> Option<()> {
 7926        if DisableAiSettings::get_global(cx).disable_ai {
 7927            return None;
 7928        }
 7929
 7930        if self.ime_transaction.is_some() {
 7931            self.discard_edit_prediction(false, cx);
 7932            return None;
 7933        }
 7934
 7935        let selection = self.selections.newest_anchor();
 7936        let cursor = selection.head();
 7937        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7938        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7939        let excerpt_id = cursor.excerpt_id;
 7940
 7941        let show_in_menu = self.show_edit_predictions_in_menu();
 7942        let completions_menu_has_precedence = !show_in_menu
 7943            && (self.context_menu.borrow().is_some()
 7944                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7945
 7946        if completions_menu_has_precedence
 7947            || !offset_selection.is_empty()
 7948            || self
 7949                .active_edit_prediction
 7950                .as_ref()
 7951                .is_some_and(|completion| {
 7952                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7953                        return false;
 7954                    };
 7955                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7956                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7957                    !invalidation_range.contains(&offset_selection.head())
 7958                })
 7959        {
 7960            self.discard_edit_prediction(false, cx);
 7961            return None;
 7962        }
 7963
 7964        self.take_active_edit_prediction(cx);
 7965        let Some(provider) = self.edit_prediction_provider() else {
 7966            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7967            return None;
 7968        };
 7969
 7970        let (buffer, cursor_buffer_position) =
 7971            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7972
 7973        self.edit_prediction_settings =
 7974            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7975
 7976        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7977
 7978        if self.edit_prediction_indent_conflict {
 7979            let cursor_point = cursor.to_point(&multibuffer);
 7980
 7981            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7982
 7983            if let Some((_, indent)) = indents.iter().next()
 7984                && indent.len == cursor_point.column
 7985            {
 7986                self.edit_prediction_indent_conflict = false;
 7987            }
 7988        }
 7989
 7990        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7991
 7992        let (completion_id, edits, edit_preview) = match edit_prediction {
 7993            edit_prediction::EditPrediction::Local {
 7994                id,
 7995                edits,
 7996                edit_preview,
 7997            } => (id, edits, edit_preview),
 7998            edit_prediction::EditPrediction::Jump {
 7999                id,
 8000                snapshot,
 8001                target,
 8002            } => {
 8003                self.stale_edit_prediction_in_menu = None;
 8004                self.active_edit_prediction = Some(EditPredictionState {
 8005                    inlay_ids: vec![],
 8006                    completion: EditPrediction::MoveOutside { snapshot, target },
 8007                    completion_id: id,
 8008                    invalidation_range: None,
 8009                });
 8010                cx.notify();
 8011                return Some(());
 8012            }
 8013        };
 8014
 8015        let edits = edits
 8016            .into_iter()
 8017            .flat_map(|(range, new_text)| {
 8018                Some((
 8019                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8020                    new_text,
 8021                ))
 8022            })
 8023            .collect::<Vec<_>>();
 8024        if edits.is_empty() {
 8025            return None;
 8026        }
 8027
 8028        let first_edit_start = edits.first().unwrap().0.start;
 8029        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8030        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8031
 8032        let last_edit_end = edits.last().unwrap().0.end;
 8033        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8034        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8035
 8036        let cursor_row = cursor.to_point(&multibuffer).row;
 8037
 8038        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8039
 8040        let mut inlay_ids = Vec::new();
 8041        let invalidation_row_range;
 8042        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8043            Some(cursor_row..edit_end_row)
 8044        } else if cursor_row > edit_end_row {
 8045            Some(edit_start_row..cursor_row)
 8046        } else {
 8047            None
 8048        };
 8049        let supports_jump = self
 8050            .edit_prediction_provider
 8051            .as_ref()
 8052            .map(|provider| provider.provider.supports_jump_to_edit())
 8053            .unwrap_or(true);
 8054
 8055        let is_move = supports_jump
 8056            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8057        let completion = if is_move {
 8058            invalidation_row_range =
 8059                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8060            let target = first_edit_start;
 8061            EditPrediction::MoveWithin { target, snapshot }
 8062        } else {
 8063            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8064                && !self.edit_predictions_hidden_for_vim_mode;
 8065
 8066            if show_completions_in_buffer {
 8067                if edits
 8068                    .iter()
 8069                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8070                {
 8071                    let mut inlays = Vec::new();
 8072                    for (range, new_text) in &edits {
 8073                        let inlay = Inlay::edit_prediction(
 8074                            post_inc(&mut self.next_inlay_id),
 8075                            range.start,
 8076                            new_text.as_str(),
 8077                        );
 8078                        inlay_ids.push(inlay.id);
 8079                        inlays.push(inlay);
 8080                    }
 8081
 8082                    self.splice_inlays(&[], inlays, cx);
 8083                } else {
 8084                    let background_color = cx.theme().status().deleted_background;
 8085                    self.highlight_text::<EditPredictionHighlight>(
 8086                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8087                        HighlightStyle {
 8088                            background_color: Some(background_color),
 8089                            ..Default::default()
 8090                        },
 8091                        cx,
 8092                    );
 8093                }
 8094            }
 8095
 8096            invalidation_row_range = edit_start_row..edit_end_row;
 8097
 8098            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8099                if provider.show_tab_accept_marker() {
 8100                    EditDisplayMode::TabAccept
 8101                } else {
 8102                    EditDisplayMode::Inline
 8103                }
 8104            } else {
 8105                EditDisplayMode::DiffPopover
 8106            };
 8107
 8108            EditPrediction::Edit {
 8109                edits,
 8110                edit_preview,
 8111                display_mode,
 8112                snapshot,
 8113            }
 8114        };
 8115
 8116        let invalidation_range = multibuffer
 8117            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8118            ..multibuffer.anchor_after(Point::new(
 8119                invalidation_row_range.end,
 8120                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8121            ));
 8122
 8123        self.stale_edit_prediction_in_menu = None;
 8124        self.active_edit_prediction = Some(EditPredictionState {
 8125            inlay_ids,
 8126            completion,
 8127            completion_id,
 8128            invalidation_range: Some(invalidation_range),
 8129        });
 8130
 8131        cx.notify();
 8132
 8133        Some(())
 8134    }
 8135
 8136    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8137        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8138    }
 8139
 8140    fn clear_tasks(&mut self) {
 8141        self.tasks.clear()
 8142    }
 8143
 8144    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8145        if self.tasks.insert(key, value).is_some() {
 8146            // This case should hopefully be rare, but just in case...
 8147            log::error!(
 8148                "multiple different run targets found on a single line, only the last target will be rendered"
 8149            )
 8150        }
 8151    }
 8152
 8153    /// Get all display points of breakpoints that will be rendered within editor
 8154    ///
 8155    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8156    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8157    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8158    fn active_breakpoints(
 8159        &self,
 8160        range: Range<DisplayRow>,
 8161        window: &mut Window,
 8162        cx: &mut Context<Self>,
 8163    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8164        let mut breakpoint_display_points = HashMap::default();
 8165
 8166        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8167            return breakpoint_display_points;
 8168        };
 8169
 8170        let snapshot = self.snapshot(window, cx);
 8171
 8172        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8173        let Some(project) = self.project() else {
 8174            return breakpoint_display_points;
 8175        };
 8176
 8177        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8178            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8179
 8180        for (buffer_snapshot, range, excerpt_id) in
 8181            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8182        {
 8183            let Some(buffer) = project
 8184                .read(cx)
 8185                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8186            else {
 8187                continue;
 8188            };
 8189            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8190                &buffer,
 8191                Some(
 8192                    buffer_snapshot.anchor_before(range.start)
 8193                        ..buffer_snapshot.anchor_after(range.end),
 8194                ),
 8195                buffer_snapshot,
 8196                cx,
 8197            );
 8198            for (breakpoint, state) in breakpoints {
 8199                let multi_buffer_anchor =
 8200                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8201                let position = multi_buffer_anchor
 8202                    .to_point(multi_buffer_snapshot)
 8203                    .to_display_point(&snapshot);
 8204
 8205                breakpoint_display_points.insert(
 8206                    position.row(),
 8207                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8208                );
 8209            }
 8210        }
 8211
 8212        breakpoint_display_points
 8213    }
 8214
 8215    fn breakpoint_context_menu(
 8216        &self,
 8217        anchor: Anchor,
 8218        window: &mut Window,
 8219        cx: &mut Context<Self>,
 8220    ) -> Entity<ui::ContextMenu> {
 8221        let weak_editor = cx.weak_entity();
 8222        let focus_handle = self.focus_handle(cx);
 8223
 8224        let row = self
 8225            .buffer
 8226            .read(cx)
 8227            .snapshot(cx)
 8228            .summary_for_anchor::<Point>(&anchor)
 8229            .row;
 8230
 8231        let breakpoint = self
 8232            .breakpoint_at_row(row, window, cx)
 8233            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8234
 8235        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8236            "Edit Log Breakpoint"
 8237        } else {
 8238            "Set Log Breakpoint"
 8239        };
 8240
 8241        let condition_breakpoint_msg = if breakpoint
 8242            .as_ref()
 8243            .is_some_and(|bp| bp.1.condition.is_some())
 8244        {
 8245            "Edit Condition Breakpoint"
 8246        } else {
 8247            "Set Condition Breakpoint"
 8248        };
 8249
 8250        let hit_condition_breakpoint_msg = if breakpoint
 8251            .as_ref()
 8252            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8253        {
 8254            "Edit Hit Condition Breakpoint"
 8255        } else {
 8256            "Set Hit Condition Breakpoint"
 8257        };
 8258
 8259        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8260            "Unset Breakpoint"
 8261        } else {
 8262            "Set Breakpoint"
 8263        };
 8264
 8265        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8266
 8267        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8268            BreakpointState::Enabled => Some("Disable"),
 8269            BreakpointState::Disabled => Some("Enable"),
 8270        });
 8271
 8272        let (anchor, breakpoint) =
 8273            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8274
 8275        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8276            menu.on_blur_subscription(Subscription::new(|| {}))
 8277                .context(focus_handle)
 8278                .when(run_to_cursor, |this| {
 8279                    let weak_editor = weak_editor.clone();
 8280                    this.entry("Run to cursor", None, move |window, cx| {
 8281                        weak_editor
 8282                            .update(cx, |editor, cx| {
 8283                                editor.change_selections(
 8284                                    SelectionEffects::no_scroll(),
 8285                                    window,
 8286                                    cx,
 8287                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8288                                );
 8289                            })
 8290                            .ok();
 8291
 8292                        window.dispatch_action(Box::new(RunToCursor), cx);
 8293                    })
 8294                    .separator()
 8295                })
 8296                .when_some(toggle_state_msg, |this, msg| {
 8297                    this.entry(msg, None, {
 8298                        let weak_editor = weak_editor.clone();
 8299                        let breakpoint = breakpoint.clone();
 8300                        move |_window, cx| {
 8301                            weak_editor
 8302                                .update(cx, |this, cx| {
 8303                                    this.edit_breakpoint_at_anchor(
 8304                                        anchor,
 8305                                        breakpoint.as_ref().clone(),
 8306                                        BreakpointEditAction::InvertState,
 8307                                        cx,
 8308                                    );
 8309                                })
 8310                                .log_err();
 8311                        }
 8312                    })
 8313                })
 8314                .entry(set_breakpoint_msg, None, {
 8315                    let weak_editor = weak_editor.clone();
 8316                    let breakpoint = breakpoint.clone();
 8317                    move |_window, cx| {
 8318                        weak_editor
 8319                            .update(cx, |this, cx| {
 8320                                this.edit_breakpoint_at_anchor(
 8321                                    anchor,
 8322                                    breakpoint.as_ref().clone(),
 8323                                    BreakpointEditAction::Toggle,
 8324                                    cx,
 8325                                );
 8326                            })
 8327                            .log_err();
 8328                    }
 8329                })
 8330                .entry(log_breakpoint_msg, None, {
 8331                    let breakpoint = breakpoint.clone();
 8332                    let weak_editor = weak_editor.clone();
 8333                    move |window, cx| {
 8334                        weak_editor
 8335                            .update(cx, |this, cx| {
 8336                                this.add_edit_breakpoint_block(
 8337                                    anchor,
 8338                                    breakpoint.as_ref(),
 8339                                    BreakpointPromptEditAction::Log,
 8340                                    window,
 8341                                    cx,
 8342                                );
 8343                            })
 8344                            .log_err();
 8345                    }
 8346                })
 8347                .entry(condition_breakpoint_msg, None, {
 8348                    let breakpoint = breakpoint.clone();
 8349                    let weak_editor = weak_editor.clone();
 8350                    move |window, cx| {
 8351                        weak_editor
 8352                            .update(cx, |this, cx| {
 8353                                this.add_edit_breakpoint_block(
 8354                                    anchor,
 8355                                    breakpoint.as_ref(),
 8356                                    BreakpointPromptEditAction::Condition,
 8357                                    window,
 8358                                    cx,
 8359                                );
 8360                            })
 8361                            .log_err();
 8362                    }
 8363                })
 8364                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8365                    weak_editor
 8366                        .update(cx, |this, cx| {
 8367                            this.add_edit_breakpoint_block(
 8368                                anchor,
 8369                                breakpoint.as_ref(),
 8370                                BreakpointPromptEditAction::HitCondition,
 8371                                window,
 8372                                cx,
 8373                            );
 8374                        })
 8375                        .log_err();
 8376                })
 8377        })
 8378    }
 8379
 8380    fn render_breakpoint(
 8381        &self,
 8382        position: Anchor,
 8383        row: DisplayRow,
 8384        breakpoint: &Breakpoint,
 8385        state: Option<BreakpointSessionState>,
 8386        cx: &mut Context<Self>,
 8387    ) -> IconButton {
 8388        let is_rejected = state.is_some_and(|s| !s.verified);
 8389        // Is it a breakpoint that shows up when hovering over gutter?
 8390        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8391            (false, false),
 8392            |PhantomBreakpointIndicator {
 8393                 is_active,
 8394                 display_row,
 8395                 collides_with_existing_breakpoint,
 8396             }| {
 8397                (
 8398                    is_active && display_row == row,
 8399                    collides_with_existing_breakpoint,
 8400                )
 8401            },
 8402        );
 8403
 8404        let (color, icon) = {
 8405            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8406                (false, false) => ui::IconName::DebugBreakpoint,
 8407                (true, false) => ui::IconName::DebugLogBreakpoint,
 8408                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8409                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8410            };
 8411
 8412            let color = if is_phantom {
 8413                Color::Hint
 8414            } else if is_rejected {
 8415                Color::Disabled
 8416            } else {
 8417                Color::Debugger
 8418            };
 8419
 8420            (color, icon)
 8421        };
 8422
 8423        let breakpoint = Arc::from(breakpoint.clone());
 8424
 8425        let alt_as_text = gpui::Keystroke {
 8426            modifiers: Modifiers::secondary_key(),
 8427            ..Default::default()
 8428        };
 8429        let primary_action_text = if breakpoint.is_disabled() {
 8430            "Enable breakpoint"
 8431        } else if is_phantom && !collides_with_existing {
 8432            "Set breakpoint"
 8433        } else {
 8434            "Unset breakpoint"
 8435        };
 8436        let focus_handle = self.focus_handle.clone();
 8437
 8438        let meta = if is_rejected {
 8439            SharedString::from("No executable code is associated with this line.")
 8440        } else if collides_with_existing && !breakpoint.is_disabled() {
 8441            SharedString::from(format!(
 8442                "{alt_as_text}-click to disable,\nright-click for more options."
 8443            ))
 8444        } else {
 8445            SharedString::from("Right-click for more options.")
 8446        };
 8447        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8448            .icon_size(IconSize::XSmall)
 8449            .size(ui::ButtonSize::None)
 8450            .when(is_rejected, |this| {
 8451                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8452            })
 8453            .icon_color(color)
 8454            .style(ButtonStyle::Transparent)
 8455            .on_click(cx.listener({
 8456                move |editor, event: &ClickEvent, window, cx| {
 8457                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8458                        BreakpointEditAction::InvertState
 8459                    } else {
 8460                        BreakpointEditAction::Toggle
 8461                    };
 8462
 8463                    window.focus(&editor.focus_handle(cx));
 8464                    editor.edit_breakpoint_at_anchor(
 8465                        position,
 8466                        breakpoint.as_ref().clone(),
 8467                        edit_action,
 8468                        cx,
 8469                    );
 8470                }
 8471            }))
 8472            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8473                editor.set_breakpoint_context_menu(
 8474                    row,
 8475                    Some(position),
 8476                    event.position(),
 8477                    window,
 8478                    cx,
 8479                );
 8480            }))
 8481            .tooltip(move |window, cx| {
 8482                Tooltip::with_meta_in(
 8483                    primary_action_text,
 8484                    Some(&ToggleBreakpoint),
 8485                    meta.clone(),
 8486                    &focus_handle,
 8487                    window,
 8488                    cx,
 8489                )
 8490            })
 8491    }
 8492
 8493    fn build_tasks_context(
 8494        project: &Entity<Project>,
 8495        buffer: &Entity<Buffer>,
 8496        buffer_row: u32,
 8497        tasks: &Arc<RunnableTasks>,
 8498        cx: &mut Context<Self>,
 8499    ) -> Task<Option<task::TaskContext>> {
 8500        let position = Point::new(buffer_row, tasks.column);
 8501        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8502        let location = Location {
 8503            buffer: buffer.clone(),
 8504            range: range_start..range_start,
 8505        };
 8506        // Fill in the environmental variables from the tree-sitter captures
 8507        let mut captured_task_variables = TaskVariables::default();
 8508        for (capture_name, value) in tasks.extra_variables.clone() {
 8509            captured_task_variables.insert(
 8510                task::VariableName::Custom(capture_name.into()),
 8511                value.clone(),
 8512            );
 8513        }
 8514        project.update(cx, |project, cx| {
 8515            project.task_store().update(cx, |task_store, cx| {
 8516                task_store.task_context_for_location(captured_task_variables, location, cx)
 8517            })
 8518        })
 8519    }
 8520
 8521    pub fn spawn_nearest_task(
 8522        &mut self,
 8523        action: &SpawnNearestTask,
 8524        window: &mut Window,
 8525        cx: &mut Context<Self>,
 8526    ) {
 8527        let Some((workspace, _)) = self.workspace.clone() else {
 8528            return;
 8529        };
 8530        let Some(project) = self.project.clone() else {
 8531            return;
 8532        };
 8533
 8534        // Try to find a closest, enclosing node using tree-sitter that has a task
 8535        let Some((buffer, buffer_row, tasks)) = self
 8536            .find_enclosing_node_task(cx)
 8537            // Or find the task that's closest in row-distance.
 8538            .or_else(|| self.find_closest_task(cx))
 8539        else {
 8540            return;
 8541        };
 8542
 8543        let reveal_strategy = action.reveal;
 8544        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8545        cx.spawn_in(window, async move |_, cx| {
 8546            let context = task_context.await?;
 8547            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8548
 8549            let resolved = &mut resolved_task.resolved;
 8550            resolved.reveal = reveal_strategy;
 8551
 8552            workspace
 8553                .update_in(cx, |workspace, window, cx| {
 8554                    workspace.schedule_resolved_task(
 8555                        task_source_kind,
 8556                        resolved_task,
 8557                        false,
 8558                        window,
 8559                        cx,
 8560                    );
 8561                })
 8562                .ok()
 8563        })
 8564        .detach();
 8565    }
 8566
 8567    fn find_closest_task(
 8568        &mut self,
 8569        cx: &mut Context<Self>,
 8570    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8571        let cursor_row = self
 8572            .selections
 8573            .newest_adjusted(&self.display_snapshot(cx))
 8574            .head()
 8575            .row;
 8576
 8577        let ((buffer_id, row), tasks) = self
 8578            .tasks
 8579            .iter()
 8580            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8581
 8582        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8583        let tasks = Arc::new(tasks.to_owned());
 8584        Some((buffer, *row, tasks))
 8585    }
 8586
 8587    fn find_enclosing_node_task(
 8588        &mut self,
 8589        cx: &mut Context<Self>,
 8590    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8591        let snapshot = self.buffer.read(cx).snapshot(cx);
 8592        let offset = self
 8593            .selections
 8594            .newest::<usize>(&self.display_snapshot(cx))
 8595            .head();
 8596        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8597        let buffer_id = excerpt.buffer().remote_id();
 8598
 8599        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8600        let mut cursor = layer.node().walk();
 8601
 8602        while cursor.goto_first_child_for_byte(offset).is_some() {
 8603            if cursor.node().end_byte() == offset {
 8604                cursor.goto_next_sibling();
 8605            }
 8606        }
 8607
 8608        // Ascend to the smallest ancestor that contains the range and has a task.
 8609        loop {
 8610            let node = cursor.node();
 8611            let node_range = node.byte_range();
 8612            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8613
 8614            // Check if this node contains our offset
 8615            if node_range.start <= offset && node_range.end >= offset {
 8616                // If it contains offset, check for task
 8617                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8618                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8619                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8620                }
 8621            }
 8622
 8623            if !cursor.goto_parent() {
 8624                break;
 8625            }
 8626        }
 8627        None
 8628    }
 8629
 8630    fn render_run_indicator(
 8631        &self,
 8632        _style: &EditorStyle,
 8633        is_active: bool,
 8634        row: DisplayRow,
 8635        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8636        cx: &mut Context<Self>,
 8637    ) -> IconButton {
 8638        let color = Color::Muted;
 8639        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8640
 8641        IconButton::new(
 8642            ("run_indicator", row.0 as usize),
 8643            ui::IconName::PlayOutlined,
 8644        )
 8645        .shape(ui::IconButtonShape::Square)
 8646        .icon_size(IconSize::XSmall)
 8647        .icon_color(color)
 8648        .toggle_state(is_active)
 8649        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8650            let quick_launch = match e {
 8651                ClickEvent::Keyboard(_) => true,
 8652                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8653            };
 8654
 8655            window.focus(&editor.focus_handle(cx));
 8656            editor.toggle_code_actions(
 8657                &ToggleCodeActions {
 8658                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8659                    quick_launch,
 8660                },
 8661                window,
 8662                cx,
 8663            );
 8664        }))
 8665        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8666            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8667        }))
 8668    }
 8669
 8670    pub fn context_menu_visible(&self) -> bool {
 8671        !self.edit_prediction_preview_is_active()
 8672            && self
 8673                .context_menu
 8674                .borrow()
 8675                .as_ref()
 8676                .is_some_and(|menu| menu.visible())
 8677    }
 8678
 8679    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8680        self.context_menu
 8681            .borrow()
 8682            .as_ref()
 8683            .map(|menu| menu.origin())
 8684    }
 8685
 8686    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8687        self.context_menu_options = Some(options);
 8688    }
 8689
 8690    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8691    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8692
 8693    fn render_edit_prediction_popover(
 8694        &mut self,
 8695        text_bounds: &Bounds<Pixels>,
 8696        content_origin: gpui::Point<Pixels>,
 8697        right_margin: Pixels,
 8698        editor_snapshot: &EditorSnapshot,
 8699        visible_row_range: Range<DisplayRow>,
 8700        scroll_top: ScrollOffset,
 8701        scroll_bottom: ScrollOffset,
 8702        line_layouts: &[LineWithInvisibles],
 8703        line_height: Pixels,
 8704        scroll_position: gpui::Point<ScrollOffset>,
 8705        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8706        newest_selection_head: Option<DisplayPoint>,
 8707        editor_width: Pixels,
 8708        style: &EditorStyle,
 8709        window: &mut Window,
 8710        cx: &mut App,
 8711    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8712        if self.mode().is_minimap() {
 8713            return None;
 8714        }
 8715        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8716
 8717        if self.edit_prediction_visible_in_cursor_popover(true) {
 8718            return None;
 8719        }
 8720
 8721        match &active_edit_prediction.completion {
 8722            EditPrediction::MoveWithin { target, .. } => {
 8723                let target_display_point = target.to_display_point(editor_snapshot);
 8724
 8725                if self.edit_prediction_requires_modifier() {
 8726                    if !self.edit_prediction_preview_is_active() {
 8727                        return None;
 8728                    }
 8729
 8730                    self.render_edit_prediction_modifier_jump_popover(
 8731                        text_bounds,
 8732                        content_origin,
 8733                        visible_row_range,
 8734                        line_layouts,
 8735                        line_height,
 8736                        scroll_pixel_position,
 8737                        newest_selection_head,
 8738                        target_display_point,
 8739                        window,
 8740                        cx,
 8741                    )
 8742                } else {
 8743                    self.render_edit_prediction_eager_jump_popover(
 8744                        text_bounds,
 8745                        content_origin,
 8746                        editor_snapshot,
 8747                        visible_row_range,
 8748                        scroll_top,
 8749                        scroll_bottom,
 8750                        line_height,
 8751                        scroll_pixel_position,
 8752                        target_display_point,
 8753                        editor_width,
 8754                        window,
 8755                        cx,
 8756                    )
 8757                }
 8758            }
 8759            EditPrediction::Edit {
 8760                display_mode: EditDisplayMode::Inline,
 8761                ..
 8762            } => None,
 8763            EditPrediction::Edit {
 8764                display_mode: EditDisplayMode::TabAccept,
 8765                edits,
 8766                ..
 8767            } => {
 8768                let range = &edits.first()?.0;
 8769                let target_display_point = range.end.to_display_point(editor_snapshot);
 8770
 8771                self.render_edit_prediction_end_of_line_popover(
 8772                    "Accept",
 8773                    editor_snapshot,
 8774                    visible_row_range,
 8775                    target_display_point,
 8776                    line_height,
 8777                    scroll_pixel_position,
 8778                    content_origin,
 8779                    editor_width,
 8780                    window,
 8781                    cx,
 8782                )
 8783            }
 8784            EditPrediction::Edit {
 8785                edits,
 8786                edit_preview,
 8787                display_mode: EditDisplayMode::DiffPopover,
 8788                snapshot,
 8789            } => self.render_edit_prediction_diff_popover(
 8790                text_bounds,
 8791                content_origin,
 8792                right_margin,
 8793                editor_snapshot,
 8794                visible_row_range,
 8795                line_layouts,
 8796                line_height,
 8797                scroll_position,
 8798                scroll_pixel_position,
 8799                newest_selection_head,
 8800                editor_width,
 8801                style,
 8802                edits,
 8803                edit_preview,
 8804                snapshot,
 8805                window,
 8806                cx,
 8807            ),
 8808            EditPrediction::MoveOutside { snapshot, .. } => {
 8809                let file_name = snapshot
 8810                    .file()
 8811                    .map(|file| file.file_name(cx))
 8812                    .unwrap_or("untitled");
 8813                let mut element = self
 8814                    .render_edit_prediction_line_popover(
 8815                        format!("Jump to {file_name}"),
 8816                        Some(IconName::ZedPredict),
 8817                        window,
 8818                        cx,
 8819                    )
 8820                    .into_any();
 8821
 8822                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8823                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8824                let origin_y = text_bounds.size.height - size.height - px(30.);
 8825                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8826                element.prepaint_at(origin, window, cx);
 8827
 8828                Some((element, origin))
 8829            }
 8830        }
 8831    }
 8832
 8833    fn render_edit_prediction_modifier_jump_popover(
 8834        &mut self,
 8835        text_bounds: &Bounds<Pixels>,
 8836        content_origin: gpui::Point<Pixels>,
 8837        visible_row_range: Range<DisplayRow>,
 8838        line_layouts: &[LineWithInvisibles],
 8839        line_height: Pixels,
 8840        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8841        newest_selection_head: Option<DisplayPoint>,
 8842        target_display_point: DisplayPoint,
 8843        window: &mut Window,
 8844        cx: &mut App,
 8845    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8846        let scrolled_content_origin =
 8847            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8848
 8849        const SCROLL_PADDING_Y: Pixels = px(12.);
 8850
 8851        if target_display_point.row() < visible_row_range.start {
 8852            return self.render_edit_prediction_scroll_popover(
 8853                |_| SCROLL_PADDING_Y,
 8854                IconName::ArrowUp,
 8855                visible_row_range,
 8856                line_layouts,
 8857                newest_selection_head,
 8858                scrolled_content_origin,
 8859                window,
 8860                cx,
 8861            );
 8862        } else if target_display_point.row() >= visible_row_range.end {
 8863            return self.render_edit_prediction_scroll_popover(
 8864                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8865                IconName::ArrowDown,
 8866                visible_row_range,
 8867                line_layouts,
 8868                newest_selection_head,
 8869                scrolled_content_origin,
 8870                window,
 8871                cx,
 8872            );
 8873        }
 8874
 8875        const POLE_WIDTH: Pixels = px(2.);
 8876
 8877        let line_layout =
 8878            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8879        let target_column = target_display_point.column() as usize;
 8880
 8881        let target_x = line_layout.x_for_index(target_column);
 8882        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8883            - scroll_pixel_position.y;
 8884
 8885        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8886
 8887        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8888        border_color.l += 0.001;
 8889
 8890        let mut element = v_flex()
 8891            .items_end()
 8892            .when(flag_on_right, |el| el.items_start())
 8893            .child(if flag_on_right {
 8894                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8895                    .rounded_bl(px(0.))
 8896                    .rounded_tl(px(0.))
 8897                    .border_l_2()
 8898                    .border_color(border_color)
 8899            } else {
 8900                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8901                    .rounded_br(px(0.))
 8902                    .rounded_tr(px(0.))
 8903                    .border_r_2()
 8904                    .border_color(border_color)
 8905            })
 8906            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8907            .into_any();
 8908
 8909        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8910
 8911        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8912            - point(
 8913                if flag_on_right {
 8914                    POLE_WIDTH
 8915                } else {
 8916                    size.width - POLE_WIDTH
 8917                },
 8918                size.height - line_height,
 8919            );
 8920
 8921        origin.x = origin.x.max(content_origin.x);
 8922
 8923        element.prepaint_at(origin, window, cx);
 8924
 8925        Some((element, origin))
 8926    }
 8927
 8928    fn render_edit_prediction_scroll_popover(
 8929        &mut self,
 8930        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8931        scroll_icon: IconName,
 8932        visible_row_range: Range<DisplayRow>,
 8933        line_layouts: &[LineWithInvisibles],
 8934        newest_selection_head: Option<DisplayPoint>,
 8935        scrolled_content_origin: gpui::Point<Pixels>,
 8936        window: &mut Window,
 8937        cx: &mut App,
 8938    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8939        let mut element = self
 8940            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8941            .into_any();
 8942
 8943        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8944
 8945        let cursor = newest_selection_head?;
 8946        let cursor_row_layout =
 8947            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8948        let cursor_column = cursor.column() as usize;
 8949
 8950        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8951
 8952        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8953
 8954        element.prepaint_at(origin, window, cx);
 8955        Some((element, origin))
 8956    }
 8957
 8958    fn render_edit_prediction_eager_jump_popover(
 8959        &mut self,
 8960        text_bounds: &Bounds<Pixels>,
 8961        content_origin: gpui::Point<Pixels>,
 8962        editor_snapshot: &EditorSnapshot,
 8963        visible_row_range: Range<DisplayRow>,
 8964        scroll_top: ScrollOffset,
 8965        scroll_bottom: ScrollOffset,
 8966        line_height: Pixels,
 8967        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8968        target_display_point: DisplayPoint,
 8969        editor_width: Pixels,
 8970        window: &mut Window,
 8971        cx: &mut App,
 8972    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8973        if target_display_point.row().as_f64() < scroll_top {
 8974            let mut element = self
 8975                .render_edit_prediction_line_popover(
 8976                    "Jump to Edit",
 8977                    Some(IconName::ArrowUp),
 8978                    window,
 8979                    cx,
 8980                )
 8981                .into_any();
 8982
 8983            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8984            let offset = point(
 8985                (text_bounds.size.width - size.width) / 2.,
 8986                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8987            );
 8988
 8989            let origin = text_bounds.origin + offset;
 8990            element.prepaint_at(origin, window, cx);
 8991            Some((element, origin))
 8992        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8993            let mut element = self
 8994                .render_edit_prediction_line_popover(
 8995                    "Jump to Edit",
 8996                    Some(IconName::ArrowDown),
 8997                    window,
 8998                    cx,
 8999                )
 9000                .into_any();
 9001
 9002            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9003            let offset = point(
 9004                (text_bounds.size.width - size.width) / 2.,
 9005                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9006            );
 9007
 9008            let origin = text_bounds.origin + offset;
 9009            element.prepaint_at(origin, window, cx);
 9010            Some((element, origin))
 9011        } else {
 9012            self.render_edit_prediction_end_of_line_popover(
 9013                "Jump to Edit",
 9014                editor_snapshot,
 9015                visible_row_range,
 9016                target_display_point,
 9017                line_height,
 9018                scroll_pixel_position,
 9019                content_origin,
 9020                editor_width,
 9021                window,
 9022                cx,
 9023            )
 9024        }
 9025    }
 9026
 9027    fn render_edit_prediction_end_of_line_popover(
 9028        self: &mut Editor,
 9029        label: &'static str,
 9030        editor_snapshot: &EditorSnapshot,
 9031        visible_row_range: Range<DisplayRow>,
 9032        target_display_point: DisplayPoint,
 9033        line_height: Pixels,
 9034        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9035        content_origin: gpui::Point<Pixels>,
 9036        editor_width: Pixels,
 9037        window: &mut Window,
 9038        cx: &mut App,
 9039    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9040        let target_line_end = DisplayPoint::new(
 9041            target_display_point.row(),
 9042            editor_snapshot.line_len(target_display_point.row()),
 9043        );
 9044
 9045        let mut element = self
 9046            .render_edit_prediction_line_popover(label, None, window, cx)
 9047            .into_any();
 9048
 9049        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9050
 9051        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9052
 9053        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9054        let mut origin = start_point
 9055            + line_origin
 9056            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9057        origin.x = origin.x.max(content_origin.x);
 9058
 9059        let max_x = content_origin.x + editor_width - size.width;
 9060
 9061        if origin.x > max_x {
 9062            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9063
 9064            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9065                origin.y += offset;
 9066                IconName::ArrowUp
 9067            } else {
 9068                origin.y -= offset;
 9069                IconName::ArrowDown
 9070            };
 9071
 9072            element = self
 9073                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9074                .into_any();
 9075
 9076            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9077
 9078            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9079        }
 9080
 9081        element.prepaint_at(origin, window, cx);
 9082        Some((element, origin))
 9083    }
 9084
 9085    fn render_edit_prediction_diff_popover(
 9086        self: &Editor,
 9087        text_bounds: &Bounds<Pixels>,
 9088        content_origin: gpui::Point<Pixels>,
 9089        right_margin: Pixels,
 9090        editor_snapshot: &EditorSnapshot,
 9091        visible_row_range: Range<DisplayRow>,
 9092        line_layouts: &[LineWithInvisibles],
 9093        line_height: Pixels,
 9094        scroll_position: gpui::Point<ScrollOffset>,
 9095        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9096        newest_selection_head: Option<DisplayPoint>,
 9097        editor_width: Pixels,
 9098        style: &EditorStyle,
 9099        edits: &Vec<(Range<Anchor>, String)>,
 9100        edit_preview: &Option<language::EditPreview>,
 9101        snapshot: &language::BufferSnapshot,
 9102        window: &mut Window,
 9103        cx: &mut App,
 9104    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9105        let edit_start = edits
 9106            .first()
 9107            .unwrap()
 9108            .0
 9109            .start
 9110            .to_display_point(editor_snapshot);
 9111        let edit_end = edits
 9112            .last()
 9113            .unwrap()
 9114            .0
 9115            .end
 9116            .to_display_point(editor_snapshot);
 9117
 9118        let is_visible = visible_row_range.contains(&edit_start.row())
 9119            || visible_row_range.contains(&edit_end.row());
 9120        if !is_visible {
 9121            return None;
 9122        }
 9123
 9124        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9125            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9126        } else {
 9127            // Fallback for providers without edit_preview
 9128            crate::edit_prediction_fallback_text(edits, cx)
 9129        };
 9130
 9131        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9132        let line_count = highlighted_edits.text.lines().count();
 9133
 9134        const BORDER_WIDTH: Pixels = px(1.);
 9135
 9136        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9137        let has_keybind = keybind.is_some();
 9138
 9139        let mut element = h_flex()
 9140            .items_start()
 9141            .child(
 9142                h_flex()
 9143                    .bg(cx.theme().colors().editor_background)
 9144                    .border(BORDER_WIDTH)
 9145                    .shadow_xs()
 9146                    .border_color(cx.theme().colors().border)
 9147                    .rounded_l_lg()
 9148                    .when(line_count > 1, |el| el.rounded_br_lg())
 9149                    .pr_1()
 9150                    .child(styled_text),
 9151            )
 9152            .child(
 9153                h_flex()
 9154                    .h(line_height + BORDER_WIDTH * 2.)
 9155                    .px_1p5()
 9156                    .gap_1()
 9157                    // Workaround: For some reason, there's a gap if we don't do this
 9158                    .ml(-BORDER_WIDTH)
 9159                    .shadow(vec![gpui::BoxShadow {
 9160                        color: gpui::black().opacity(0.05),
 9161                        offset: point(px(1.), px(1.)),
 9162                        blur_radius: px(2.),
 9163                        spread_radius: px(0.),
 9164                    }])
 9165                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9166                    .border(BORDER_WIDTH)
 9167                    .border_color(cx.theme().colors().border)
 9168                    .rounded_r_lg()
 9169                    .id("edit_prediction_diff_popover_keybind")
 9170                    .when(!has_keybind, |el| {
 9171                        let status_colors = cx.theme().status();
 9172
 9173                        el.bg(status_colors.error_background)
 9174                            .border_color(status_colors.error.opacity(0.6))
 9175                            .child(Icon::new(IconName::Info).color(Color::Error))
 9176                            .cursor_default()
 9177                            .hoverable_tooltip(move |_window, cx| {
 9178                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9179                            })
 9180                    })
 9181                    .children(keybind),
 9182            )
 9183            .into_any();
 9184
 9185        let longest_row =
 9186            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9187        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9188            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9189        } else {
 9190            layout_line(
 9191                longest_row,
 9192                editor_snapshot,
 9193                style,
 9194                editor_width,
 9195                |_| false,
 9196                window,
 9197                cx,
 9198            )
 9199            .width
 9200        };
 9201
 9202        let viewport_bounds =
 9203            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9204                right: -right_margin,
 9205                ..Default::default()
 9206            });
 9207
 9208        let x_after_longest = Pixels::from(
 9209            ScrollPixelOffset::from(
 9210                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9211            ) - scroll_pixel_position.x,
 9212        );
 9213
 9214        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9215
 9216        // Fully visible if it can be displayed within the window (allow overlapping other
 9217        // panes). However, this is only allowed if the popover starts within text_bounds.
 9218        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9219            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9220
 9221        let mut origin = if can_position_to_the_right {
 9222            point(
 9223                x_after_longest,
 9224                text_bounds.origin.y
 9225                    + Pixels::from(
 9226                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9227                            - scroll_pixel_position.y,
 9228                    ),
 9229            )
 9230        } else {
 9231            let cursor_row = newest_selection_head.map(|head| head.row());
 9232            let above_edit = edit_start
 9233                .row()
 9234                .0
 9235                .checked_sub(line_count as u32)
 9236                .map(DisplayRow);
 9237            let below_edit = Some(edit_end.row() + 1);
 9238            let above_cursor =
 9239                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9240            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9241
 9242            // Place the edit popover adjacent to the edit if there is a location
 9243            // available that is onscreen and does not obscure the cursor. Otherwise,
 9244            // place it adjacent to the cursor.
 9245            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9246                .into_iter()
 9247                .flatten()
 9248                .find(|&start_row| {
 9249                    let end_row = start_row + line_count as u32;
 9250                    visible_row_range.contains(&start_row)
 9251                        && visible_row_range.contains(&end_row)
 9252                        && cursor_row
 9253                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9254                })?;
 9255
 9256            content_origin
 9257                + point(
 9258                    Pixels::from(-scroll_pixel_position.x),
 9259                    Pixels::from(
 9260                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9261                    ),
 9262                )
 9263        };
 9264
 9265        origin.x -= BORDER_WIDTH;
 9266
 9267        window.defer_draw(element, origin, 1);
 9268
 9269        // Do not return an element, since it will already be drawn due to defer_draw.
 9270        None
 9271    }
 9272
 9273    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9274        px(30.)
 9275    }
 9276
 9277    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9278        if self.read_only(cx) {
 9279            cx.theme().players().read_only()
 9280        } else {
 9281            self.style.as_ref().unwrap().local_player
 9282        }
 9283    }
 9284
 9285    fn render_edit_prediction_accept_keybind(
 9286        &self,
 9287        window: &mut Window,
 9288        cx: &App,
 9289    ) -> Option<AnyElement> {
 9290        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9291        let accept_keystroke = accept_binding.keystroke()?;
 9292
 9293        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9294
 9295        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9296            Color::Accent
 9297        } else {
 9298            Color::Muted
 9299        };
 9300
 9301        h_flex()
 9302            .px_0p5()
 9303            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9304            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9305            .text_size(TextSize::XSmall.rems(cx))
 9306            .child(h_flex().children(ui::render_modifiers(
 9307                accept_keystroke.modifiers(),
 9308                PlatformStyle::platform(),
 9309                Some(modifiers_color),
 9310                Some(IconSize::XSmall.rems().into()),
 9311                true,
 9312            )))
 9313            .when(is_platform_style_mac, |parent| {
 9314                parent.child(accept_keystroke.key().to_string())
 9315            })
 9316            .when(!is_platform_style_mac, |parent| {
 9317                parent.child(
 9318                    Key::new(
 9319                        util::capitalize(accept_keystroke.key()),
 9320                        Some(Color::Default),
 9321                    )
 9322                    .size(Some(IconSize::XSmall.rems().into())),
 9323                )
 9324            })
 9325            .into_any()
 9326            .into()
 9327    }
 9328
 9329    fn render_edit_prediction_line_popover(
 9330        &self,
 9331        label: impl Into<SharedString>,
 9332        icon: Option<IconName>,
 9333        window: &mut Window,
 9334        cx: &App,
 9335    ) -> Stateful<Div> {
 9336        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9337
 9338        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9339        let has_keybind = keybind.is_some();
 9340
 9341        h_flex()
 9342            .id("ep-line-popover")
 9343            .py_0p5()
 9344            .pl_1()
 9345            .pr(padding_right)
 9346            .gap_1()
 9347            .rounded_md()
 9348            .border_1()
 9349            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9350            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9351            .shadow_xs()
 9352            .when(!has_keybind, |el| {
 9353                let status_colors = cx.theme().status();
 9354
 9355                el.bg(status_colors.error_background)
 9356                    .border_color(status_colors.error.opacity(0.6))
 9357                    .pl_2()
 9358                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9359                    .cursor_default()
 9360                    .hoverable_tooltip(move |_window, cx| {
 9361                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9362                    })
 9363            })
 9364            .children(keybind)
 9365            .child(
 9366                Label::new(label)
 9367                    .size(LabelSize::Small)
 9368                    .when(!has_keybind, |el| {
 9369                        el.color(cx.theme().status().error.into()).strikethrough()
 9370                    }),
 9371            )
 9372            .when(!has_keybind, |el| {
 9373                el.child(
 9374                    h_flex().ml_1().child(
 9375                        Icon::new(IconName::Info)
 9376                            .size(IconSize::Small)
 9377                            .color(cx.theme().status().error.into()),
 9378                    ),
 9379                )
 9380            })
 9381            .when_some(icon, |element, icon| {
 9382                element.child(
 9383                    div()
 9384                        .mt(px(1.5))
 9385                        .child(Icon::new(icon).size(IconSize::Small)),
 9386                )
 9387            })
 9388    }
 9389
 9390    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9391        let accent_color = cx.theme().colors().text_accent;
 9392        let editor_bg_color = cx.theme().colors().editor_background;
 9393        editor_bg_color.blend(accent_color.opacity(0.1))
 9394    }
 9395
 9396    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9397        let accent_color = cx.theme().colors().text_accent;
 9398        let editor_bg_color = cx.theme().colors().editor_background;
 9399        editor_bg_color.blend(accent_color.opacity(0.6))
 9400    }
 9401    fn get_prediction_provider_icon_name(
 9402        provider: &Option<RegisteredEditPredictionProvider>,
 9403    ) -> IconName {
 9404        match provider {
 9405            Some(provider) => match provider.provider.name() {
 9406                "copilot" => IconName::Copilot,
 9407                "supermaven" => IconName::Supermaven,
 9408                _ => IconName::ZedPredict,
 9409            },
 9410            None => IconName::ZedPredict,
 9411        }
 9412    }
 9413
 9414    fn render_edit_prediction_cursor_popover(
 9415        &self,
 9416        min_width: Pixels,
 9417        max_width: Pixels,
 9418        cursor_point: Point,
 9419        style: &EditorStyle,
 9420        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9421        _window: &Window,
 9422        cx: &mut Context<Editor>,
 9423    ) -> Option<AnyElement> {
 9424        let provider = self.edit_prediction_provider.as_ref()?;
 9425        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9426
 9427        let is_refreshing = provider.provider.is_refreshing(cx);
 9428
 9429        fn pending_completion_container(icon: IconName) -> Div {
 9430            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9431        }
 9432
 9433        let completion = match &self.active_edit_prediction {
 9434            Some(prediction) => {
 9435                if !self.has_visible_completions_menu() {
 9436                    const RADIUS: Pixels = px(6.);
 9437                    const BORDER_WIDTH: Pixels = px(1.);
 9438
 9439                    return Some(
 9440                        h_flex()
 9441                            .elevation_2(cx)
 9442                            .border(BORDER_WIDTH)
 9443                            .border_color(cx.theme().colors().border)
 9444                            .when(accept_keystroke.is_none(), |el| {
 9445                                el.border_color(cx.theme().status().error)
 9446                            })
 9447                            .rounded(RADIUS)
 9448                            .rounded_tl(px(0.))
 9449                            .overflow_hidden()
 9450                            .child(div().px_1p5().child(match &prediction.completion {
 9451                                EditPrediction::MoveWithin { target, snapshot } => {
 9452                                    use text::ToPoint as _;
 9453                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9454                                    {
 9455                                        Icon::new(IconName::ZedPredictDown)
 9456                                    } else {
 9457                                        Icon::new(IconName::ZedPredictUp)
 9458                                    }
 9459                                }
 9460                                EditPrediction::MoveOutside { .. } => {
 9461                                    // TODO [zeta2] custom icon for external jump?
 9462                                    Icon::new(provider_icon)
 9463                                }
 9464                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9465                            }))
 9466                            .child(
 9467                                h_flex()
 9468                                    .gap_1()
 9469                                    .py_1()
 9470                                    .px_2()
 9471                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9472                                    .border_l_1()
 9473                                    .border_color(cx.theme().colors().border)
 9474                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9475                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9476                                        el.child(
 9477                                            Label::new("Hold")
 9478                                                .size(LabelSize::Small)
 9479                                                .when(accept_keystroke.is_none(), |el| {
 9480                                                    el.strikethrough()
 9481                                                })
 9482                                                .line_height_style(LineHeightStyle::UiLabel),
 9483                                        )
 9484                                    })
 9485                                    .id("edit_prediction_cursor_popover_keybind")
 9486                                    .when(accept_keystroke.is_none(), |el| {
 9487                                        let status_colors = cx.theme().status();
 9488
 9489                                        el.bg(status_colors.error_background)
 9490                                            .border_color(status_colors.error.opacity(0.6))
 9491                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9492                                            .cursor_default()
 9493                                            .hoverable_tooltip(move |_window, cx| {
 9494                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9495                                                    .into()
 9496                                            })
 9497                                    })
 9498                                    .when_some(
 9499                                        accept_keystroke.as_ref(),
 9500                                        |el, accept_keystroke| {
 9501                                            el.child(h_flex().children(ui::render_modifiers(
 9502                                                accept_keystroke.modifiers(),
 9503                                                PlatformStyle::platform(),
 9504                                                Some(Color::Default),
 9505                                                Some(IconSize::XSmall.rems().into()),
 9506                                                false,
 9507                                            )))
 9508                                        },
 9509                                    ),
 9510                            )
 9511                            .into_any(),
 9512                    );
 9513                }
 9514
 9515                self.render_edit_prediction_cursor_popover_preview(
 9516                    prediction,
 9517                    cursor_point,
 9518                    style,
 9519                    cx,
 9520                )?
 9521            }
 9522
 9523            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9524                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9525                    stale_completion,
 9526                    cursor_point,
 9527                    style,
 9528                    cx,
 9529                )?,
 9530
 9531                None => pending_completion_container(provider_icon)
 9532                    .child(Label::new("...").size(LabelSize::Small)),
 9533            },
 9534
 9535            None => pending_completion_container(provider_icon)
 9536                .child(Label::new("...").size(LabelSize::Small)),
 9537        };
 9538
 9539        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9540            completion
 9541                .with_animation(
 9542                    "loading-completion",
 9543                    Animation::new(Duration::from_secs(2))
 9544                        .repeat()
 9545                        .with_easing(pulsating_between(0.4, 0.8)),
 9546                    |label, delta| label.opacity(delta),
 9547                )
 9548                .into_any_element()
 9549        } else {
 9550            completion.into_any_element()
 9551        };
 9552
 9553        let has_completion = self.active_edit_prediction.is_some();
 9554
 9555        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9556        Some(
 9557            h_flex()
 9558                .min_w(min_width)
 9559                .max_w(max_width)
 9560                .flex_1()
 9561                .elevation_2(cx)
 9562                .border_color(cx.theme().colors().border)
 9563                .child(
 9564                    div()
 9565                        .flex_1()
 9566                        .py_1()
 9567                        .px_2()
 9568                        .overflow_hidden()
 9569                        .child(completion),
 9570                )
 9571                .when_some(accept_keystroke, |el, accept_keystroke| {
 9572                    if !accept_keystroke.modifiers().modified() {
 9573                        return el;
 9574                    }
 9575
 9576                    el.child(
 9577                        h_flex()
 9578                            .h_full()
 9579                            .border_l_1()
 9580                            .rounded_r_lg()
 9581                            .border_color(cx.theme().colors().border)
 9582                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9583                            .gap_1()
 9584                            .py_1()
 9585                            .px_2()
 9586                            .child(
 9587                                h_flex()
 9588                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9589                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9590                                    .child(h_flex().children(ui::render_modifiers(
 9591                                        accept_keystroke.modifiers(),
 9592                                        PlatformStyle::platform(),
 9593                                        Some(if !has_completion {
 9594                                            Color::Muted
 9595                                        } else {
 9596                                            Color::Default
 9597                                        }),
 9598                                        None,
 9599                                        false,
 9600                                    ))),
 9601                            )
 9602                            .child(Label::new("Preview").into_any_element())
 9603                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9604                    )
 9605                })
 9606                .into_any(),
 9607        )
 9608    }
 9609
 9610    fn render_edit_prediction_cursor_popover_preview(
 9611        &self,
 9612        completion: &EditPredictionState,
 9613        cursor_point: Point,
 9614        style: &EditorStyle,
 9615        cx: &mut Context<Editor>,
 9616    ) -> Option<Div> {
 9617        use text::ToPoint as _;
 9618
 9619        fn render_relative_row_jump(
 9620            prefix: impl Into<String>,
 9621            current_row: u32,
 9622            target_row: u32,
 9623        ) -> Div {
 9624            let (row_diff, arrow) = if target_row < current_row {
 9625                (current_row - target_row, IconName::ArrowUp)
 9626            } else {
 9627                (target_row - current_row, IconName::ArrowDown)
 9628            };
 9629
 9630            h_flex()
 9631                .child(
 9632                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9633                        .color(Color::Muted)
 9634                        .size(LabelSize::Small),
 9635                )
 9636                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9637        }
 9638
 9639        let supports_jump = self
 9640            .edit_prediction_provider
 9641            .as_ref()
 9642            .map(|provider| provider.provider.supports_jump_to_edit())
 9643            .unwrap_or(true);
 9644
 9645        match &completion.completion {
 9646            EditPrediction::MoveWithin {
 9647                target, snapshot, ..
 9648            } => {
 9649                if !supports_jump {
 9650                    return None;
 9651                }
 9652
 9653                Some(
 9654                    h_flex()
 9655                        .px_2()
 9656                        .gap_2()
 9657                        .flex_1()
 9658                        .child(
 9659                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9660                                Icon::new(IconName::ZedPredictDown)
 9661                            } else {
 9662                                Icon::new(IconName::ZedPredictUp)
 9663                            },
 9664                        )
 9665                        .child(Label::new("Jump to Edit")),
 9666                )
 9667            }
 9668            EditPrediction::MoveOutside { snapshot, .. } => {
 9669                let file_name = snapshot
 9670                    .file()
 9671                    .map(|file| file.file_name(cx))
 9672                    .unwrap_or("untitled");
 9673                Some(
 9674                    h_flex()
 9675                        .px_2()
 9676                        .gap_2()
 9677                        .flex_1()
 9678                        .child(Icon::new(IconName::ZedPredict))
 9679                        .child(Label::new(format!("Jump to {file_name}"))),
 9680                )
 9681            }
 9682            EditPrediction::Edit {
 9683                edits,
 9684                edit_preview,
 9685                snapshot,
 9686                display_mode: _,
 9687            } => {
 9688                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9689
 9690                let (highlighted_edits, has_more_lines) =
 9691                    if let Some(edit_preview) = edit_preview.as_ref() {
 9692                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9693                            .first_line_preview()
 9694                    } else {
 9695                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9696                    };
 9697
 9698                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9699                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9700
 9701                let preview = h_flex()
 9702                    .gap_1()
 9703                    .min_w_16()
 9704                    .child(styled_text)
 9705                    .when(has_more_lines, |parent| parent.child(""));
 9706
 9707                let left = if supports_jump && first_edit_row != cursor_point.row {
 9708                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9709                        .into_any_element()
 9710                } else {
 9711                    let icon_name =
 9712                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9713                    Icon::new(icon_name).into_any_element()
 9714                };
 9715
 9716                Some(
 9717                    h_flex()
 9718                        .h_full()
 9719                        .flex_1()
 9720                        .gap_2()
 9721                        .pr_1()
 9722                        .overflow_x_hidden()
 9723                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9724                        .child(left)
 9725                        .child(preview),
 9726                )
 9727            }
 9728        }
 9729    }
 9730
 9731    pub fn render_context_menu(
 9732        &self,
 9733        style: &EditorStyle,
 9734        max_height_in_lines: u32,
 9735        window: &mut Window,
 9736        cx: &mut Context<Editor>,
 9737    ) -> Option<AnyElement> {
 9738        let menu = self.context_menu.borrow();
 9739        let menu = menu.as_ref()?;
 9740        if !menu.visible() {
 9741            return None;
 9742        };
 9743        Some(menu.render(style, max_height_in_lines, window, cx))
 9744    }
 9745
 9746    fn render_context_menu_aside(
 9747        &mut self,
 9748        max_size: Size<Pixels>,
 9749        window: &mut Window,
 9750        cx: &mut Context<Editor>,
 9751    ) -> Option<AnyElement> {
 9752        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9753            if menu.visible() {
 9754                menu.render_aside(max_size, window, cx)
 9755            } else {
 9756                None
 9757            }
 9758        })
 9759    }
 9760
 9761    fn hide_context_menu(
 9762        &mut self,
 9763        window: &mut Window,
 9764        cx: &mut Context<Self>,
 9765    ) -> Option<CodeContextMenu> {
 9766        cx.notify();
 9767        self.completion_tasks.clear();
 9768        let context_menu = self.context_menu.borrow_mut().take();
 9769        self.stale_edit_prediction_in_menu.take();
 9770        self.update_visible_edit_prediction(window, cx);
 9771        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9772            && let Some(completion_provider) = &self.completion_provider
 9773        {
 9774            completion_provider.selection_changed(None, window, cx);
 9775        }
 9776        context_menu
 9777    }
 9778
 9779    fn show_snippet_choices(
 9780        &mut self,
 9781        choices: &Vec<String>,
 9782        selection: Range<Anchor>,
 9783        cx: &mut Context<Self>,
 9784    ) {
 9785        let Some((_, buffer, _)) = self
 9786            .buffer()
 9787            .read(cx)
 9788            .excerpt_containing(selection.start, cx)
 9789        else {
 9790            return;
 9791        };
 9792        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9793        else {
 9794            return;
 9795        };
 9796        if buffer != end_buffer {
 9797            log::error!("expected anchor range to have matching buffer IDs");
 9798            return;
 9799        }
 9800
 9801        let id = post_inc(&mut self.next_completion_id);
 9802        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9803        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9804            CompletionsMenu::new_snippet_choices(
 9805                id,
 9806                true,
 9807                choices,
 9808                selection,
 9809                buffer,
 9810                snippet_sort_order,
 9811            ),
 9812        ));
 9813    }
 9814
 9815    pub fn insert_snippet(
 9816        &mut self,
 9817        insertion_ranges: &[Range<usize>],
 9818        snippet: Snippet,
 9819        window: &mut Window,
 9820        cx: &mut Context<Self>,
 9821    ) -> Result<()> {
 9822        struct Tabstop<T> {
 9823            is_end_tabstop: bool,
 9824            ranges: Vec<Range<T>>,
 9825            choices: Option<Vec<String>>,
 9826        }
 9827
 9828        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9829            let snippet_text: Arc<str> = snippet.text.clone().into();
 9830            let edits = insertion_ranges
 9831                .iter()
 9832                .cloned()
 9833                .map(|range| (range, snippet_text.clone()));
 9834            let autoindent_mode = AutoindentMode::Block {
 9835                original_indent_columns: Vec::new(),
 9836            };
 9837            buffer.edit(edits, Some(autoindent_mode), cx);
 9838
 9839            let snapshot = &*buffer.read(cx);
 9840            let snippet = &snippet;
 9841            snippet
 9842                .tabstops
 9843                .iter()
 9844                .map(|tabstop| {
 9845                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9846                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9847                    });
 9848                    let mut tabstop_ranges = tabstop
 9849                        .ranges
 9850                        .iter()
 9851                        .flat_map(|tabstop_range| {
 9852                            let mut delta = 0_isize;
 9853                            insertion_ranges.iter().map(move |insertion_range| {
 9854                                let insertion_start = insertion_range.start as isize + delta;
 9855                                delta +=
 9856                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9857
 9858                                let start = ((insertion_start + tabstop_range.start) as usize)
 9859                                    .min(snapshot.len());
 9860                                let end = ((insertion_start + tabstop_range.end) as usize)
 9861                                    .min(snapshot.len());
 9862                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9863                            })
 9864                        })
 9865                        .collect::<Vec<_>>();
 9866                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9867
 9868                    Tabstop {
 9869                        is_end_tabstop,
 9870                        ranges: tabstop_ranges,
 9871                        choices: tabstop.choices.clone(),
 9872                    }
 9873                })
 9874                .collect::<Vec<_>>()
 9875        });
 9876        if let Some(tabstop) = tabstops.first() {
 9877            self.change_selections(Default::default(), window, cx, |s| {
 9878                // Reverse order so that the first range is the newest created selection.
 9879                // Completions will use it and autoscroll will prioritize it.
 9880                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9881            });
 9882
 9883            if let Some(choices) = &tabstop.choices
 9884                && let Some(selection) = tabstop.ranges.first()
 9885            {
 9886                self.show_snippet_choices(choices, selection.clone(), cx)
 9887            }
 9888
 9889            // If we're already at the last tabstop and it's at the end of the snippet,
 9890            // we're done, we don't need to keep the state around.
 9891            if !tabstop.is_end_tabstop {
 9892                let choices = tabstops
 9893                    .iter()
 9894                    .map(|tabstop| tabstop.choices.clone())
 9895                    .collect();
 9896
 9897                let ranges = tabstops
 9898                    .into_iter()
 9899                    .map(|tabstop| tabstop.ranges)
 9900                    .collect::<Vec<_>>();
 9901
 9902                self.snippet_stack.push(SnippetState {
 9903                    active_index: 0,
 9904                    ranges,
 9905                    choices,
 9906                });
 9907            }
 9908
 9909            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9910            if self.autoclose_regions.is_empty() {
 9911                let snapshot = self.buffer.read(cx).snapshot(cx);
 9912                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9913                    let selection_head = selection.head();
 9914                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9915                        continue;
 9916                    };
 9917
 9918                    let mut bracket_pair = None;
 9919                    let max_lookup_length = scope
 9920                        .brackets()
 9921                        .map(|(pair, _)| {
 9922                            pair.start
 9923                                .as_str()
 9924                                .chars()
 9925                                .count()
 9926                                .max(pair.end.as_str().chars().count())
 9927                        })
 9928                        .max();
 9929                    if let Some(max_lookup_length) = max_lookup_length {
 9930                        let next_text = snapshot
 9931                            .chars_at(selection_head)
 9932                            .take(max_lookup_length)
 9933                            .collect::<String>();
 9934                        let prev_text = snapshot
 9935                            .reversed_chars_at(selection_head)
 9936                            .take(max_lookup_length)
 9937                            .collect::<String>();
 9938
 9939                        for (pair, enabled) in scope.brackets() {
 9940                            if enabled
 9941                                && pair.close
 9942                                && prev_text.starts_with(pair.start.as_str())
 9943                                && next_text.starts_with(pair.end.as_str())
 9944                            {
 9945                                bracket_pair = Some(pair.clone());
 9946                                break;
 9947                            }
 9948                        }
 9949                    }
 9950
 9951                    if let Some(pair) = bracket_pair {
 9952                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9953                        let autoclose_enabled =
 9954                            self.use_autoclose && snapshot_settings.use_autoclose;
 9955                        if autoclose_enabled {
 9956                            let start = snapshot.anchor_after(selection_head);
 9957                            let end = snapshot.anchor_after(selection_head);
 9958                            self.autoclose_regions.push(AutocloseRegion {
 9959                                selection_id: selection.id,
 9960                                range: start..end,
 9961                                pair,
 9962                            });
 9963                        }
 9964                    }
 9965                }
 9966            }
 9967        }
 9968        Ok(())
 9969    }
 9970
 9971    pub fn move_to_next_snippet_tabstop(
 9972        &mut self,
 9973        window: &mut Window,
 9974        cx: &mut Context<Self>,
 9975    ) -> bool {
 9976        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9977    }
 9978
 9979    pub fn move_to_prev_snippet_tabstop(
 9980        &mut self,
 9981        window: &mut Window,
 9982        cx: &mut Context<Self>,
 9983    ) -> bool {
 9984        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9985    }
 9986
 9987    pub fn move_to_snippet_tabstop(
 9988        &mut self,
 9989        bias: Bias,
 9990        window: &mut Window,
 9991        cx: &mut Context<Self>,
 9992    ) -> bool {
 9993        if let Some(mut snippet) = self.snippet_stack.pop() {
 9994            match bias {
 9995                Bias::Left => {
 9996                    if snippet.active_index > 0 {
 9997                        snippet.active_index -= 1;
 9998                    } else {
 9999                        self.snippet_stack.push(snippet);
10000                        return false;
10001                    }
10002                }
10003                Bias::Right => {
10004                    if snippet.active_index + 1 < snippet.ranges.len() {
10005                        snippet.active_index += 1;
10006                    } else {
10007                        self.snippet_stack.push(snippet);
10008                        return false;
10009                    }
10010                }
10011            }
10012            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10013                self.change_selections(Default::default(), window, cx, |s| {
10014                    // Reverse order so that the first range is the newest created selection.
10015                    // Completions will use it and autoscroll will prioritize it.
10016                    s.select_ranges(current_ranges.iter().rev().cloned())
10017                });
10018
10019                if let Some(choices) = &snippet.choices[snippet.active_index]
10020                    && let Some(selection) = current_ranges.first()
10021                {
10022                    self.show_snippet_choices(choices, selection.clone(), cx);
10023                }
10024
10025                // If snippet state is not at the last tabstop, push it back on the stack
10026                if snippet.active_index + 1 < snippet.ranges.len() {
10027                    self.snippet_stack.push(snippet);
10028                }
10029                return true;
10030            }
10031        }
10032
10033        false
10034    }
10035
10036    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10037        self.transact(window, cx, |this, window, cx| {
10038            this.select_all(&SelectAll, window, cx);
10039            this.insert("", window, cx);
10040        });
10041    }
10042
10043    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10044        if self.read_only(cx) {
10045            return;
10046        }
10047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10048        self.transact(window, cx, |this, window, cx| {
10049            this.select_autoclose_pair(window, cx);
10050
10051            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10052
10053            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10054            if !this.linked_edit_ranges.is_empty() {
10055                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10056                let snapshot = this.buffer.read(cx).snapshot(cx);
10057
10058                for selection in selections.iter() {
10059                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10060                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10061                    if selection_start.buffer_id != selection_end.buffer_id {
10062                        continue;
10063                    }
10064                    if let Some(ranges) =
10065                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10066                    {
10067                        for (buffer, entries) in ranges {
10068                            linked_ranges.entry(buffer).or_default().extend(entries);
10069                        }
10070                    }
10071                }
10072            }
10073
10074            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10075            for selection in &mut selections {
10076                if selection.is_empty() {
10077                    let old_head = selection.head();
10078                    let mut new_head =
10079                        movement::left(&display_map, old_head.to_display_point(&display_map))
10080                            .to_point(&display_map);
10081                    if let Some((buffer, line_buffer_range)) = display_map
10082                        .buffer_snapshot()
10083                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10084                    {
10085                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10086                        let indent_len = match indent_size.kind {
10087                            IndentKind::Space => {
10088                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10089                            }
10090                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10091                        };
10092                        if old_head.column <= indent_size.len && old_head.column > 0 {
10093                            let indent_len = indent_len.get();
10094                            new_head = cmp::min(
10095                                new_head,
10096                                MultiBufferPoint::new(
10097                                    old_head.row,
10098                                    ((old_head.column - 1) / indent_len) * indent_len,
10099                                ),
10100                            );
10101                        }
10102                    }
10103
10104                    selection.set_head(new_head, SelectionGoal::None);
10105                }
10106            }
10107
10108            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10109            this.insert("", window, cx);
10110            let empty_str: Arc<str> = Arc::from("");
10111            for (buffer, edits) in linked_ranges {
10112                let snapshot = buffer.read(cx).snapshot();
10113                use text::ToPoint as TP;
10114
10115                let edits = edits
10116                    .into_iter()
10117                    .map(|range| {
10118                        let end_point = TP::to_point(&range.end, &snapshot);
10119                        let mut start_point = TP::to_point(&range.start, &snapshot);
10120
10121                        if end_point == start_point {
10122                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10123                                .saturating_sub(1);
10124                            start_point =
10125                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10126                        };
10127
10128                        (start_point..end_point, empty_str.clone())
10129                    })
10130                    .sorted_by_key(|(range, _)| range.start)
10131                    .collect::<Vec<_>>();
10132                buffer.update(cx, |this, cx| {
10133                    this.edit(edits, None, cx);
10134                })
10135            }
10136            this.refresh_edit_prediction(true, false, window, cx);
10137            refresh_linked_ranges(this, window, cx);
10138        });
10139    }
10140
10141    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10142        if self.read_only(cx) {
10143            return;
10144        }
10145        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10146        self.transact(window, cx, |this, window, cx| {
10147            this.change_selections(Default::default(), window, cx, |s| {
10148                s.move_with(|map, selection| {
10149                    if selection.is_empty() {
10150                        let cursor = movement::right(map, selection.head());
10151                        selection.end = cursor;
10152                        selection.reversed = true;
10153                        selection.goal = SelectionGoal::None;
10154                    }
10155                })
10156            });
10157            this.insert("", window, cx);
10158            this.refresh_edit_prediction(true, false, window, cx);
10159        });
10160    }
10161
10162    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10163        if self.mode.is_single_line() {
10164            cx.propagate();
10165            return;
10166        }
10167
10168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10169        if self.move_to_prev_snippet_tabstop(window, cx) {
10170            return;
10171        }
10172        self.outdent(&Outdent, window, cx);
10173    }
10174
10175    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10176        if self.mode.is_single_line() {
10177            cx.propagate();
10178            return;
10179        }
10180
10181        if self.move_to_next_snippet_tabstop(window, cx) {
10182            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10183            return;
10184        }
10185        if self.read_only(cx) {
10186            return;
10187        }
10188        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10189        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10190        let buffer = self.buffer.read(cx);
10191        let snapshot = buffer.snapshot(cx);
10192        let rows_iter = selections.iter().map(|s| s.head().row);
10193        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10194
10195        let has_some_cursor_in_whitespace = selections
10196            .iter()
10197            .filter(|selection| selection.is_empty())
10198            .any(|selection| {
10199                let cursor = selection.head();
10200                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10201                cursor.column < current_indent.len
10202            });
10203
10204        let mut edits = Vec::new();
10205        let mut prev_edited_row = 0;
10206        let mut row_delta = 0;
10207        for selection in &mut selections {
10208            if selection.start.row != prev_edited_row {
10209                row_delta = 0;
10210            }
10211            prev_edited_row = selection.end.row;
10212
10213            // If the selection is non-empty, then increase the indentation of the selected lines.
10214            if !selection.is_empty() {
10215                row_delta =
10216                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10217                continue;
10218            }
10219
10220            let cursor = selection.head();
10221            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10222            if let Some(suggested_indent) =
10223                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10224            {
10225                // Don't do anything if already at suggested indent
10226                // and there is any other cursor which is not
10227                if has_some_cursor_in_whitespace
10228                    && cursor.column == current_indent.len
10229                    && current_indent.len == suggested_indent.len
10230                {
10231                    continue;
10232                }
10233
10234                // Adjust line and move cursor to suggested indent
10235                // if cursor is not at suggested indent
10236                if cursor.column < suggested_indent.len
10237                    && cursor.column <= current_indent.len
10238                    && current_indent.len <= suggested_indent.len
10239                {
10240                    selection.start = Point::new(cursor.row, suggested_indent.len);
10241                    selection.end = selection.start;
10242                    if row_delta == 0 {
10243                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10244                            cursor.row,
10245                            current_indent,
10246                            suggested_indent,
10247                        ));
10248                        row_delta = suggested_indent.len - current_indent.len;
10249                    }
10250                    continue;
10251                }
10252
10253                // If current indent is more than suggested indent
10254                // only move cursor to current indent and skip indent
10255                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10256                    selection.start = Point::new(cursor.row, current_indent.len);
10257                    selection.end = selection.start;
10258                    continue;
10259                }
10260            }
10261
10262            // Otherwise, insert a hard or soft tab.
10263            let settings = buffer.language_settings_at(cursor, cx);
10264            let tab_size = if settings.hard_tabs {
10265                IndentSize::tab()
10266            } else {
10267                let tab_size = settings.tab_size.get();
10268                let indent_remainder = snapshot
10269                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10270                    .flat_map(str::chars)
10271                    .fold(row_delta % tab_size, |counter: u32, c| {
10272                        if c == '\t' {
10273                            0
10274                        } else {
10275                            (counter + 1) % tab_size
10276                        }
10277                    });
10278
10279                let chars_to_next_tab_stop = tab_size - indent_remainder;
10280                IndentSize::spaces(chars_to_next_tab_stop)
10281            };
10282            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10283            selection.end = selection.start;
10284            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10285            row_delta += tab_size.len;
10286        }
10287
10288        self.transact(window, cx, |this, window, cx| {
10289            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10290            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10291            this.refresh_edit_prediction(true, false, window, cx);
10292        });
10293    }
10294
10295    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10296        if self.read_only(cx) {
10297            return;
10298        }
10299        if self.mode.is_single_line() {
10300            cx.propagate();
10301            return;
10302        }
10303
10304        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10305        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10306        let mut prev_edited_row = 0;
10307        let mut row_delta = 0;
10308        let mut edits = Vec::new();
10309        let buffer = self.buffer.read(cx);
10310        let snapshot = buffer.snapshot(cx);
10311        for selection in &mut selections {
10312            if selection.start.row != prev_edited_row {
10313                row_delta = 0;
10314            }
10315            prev_edited_row = selection.end.row;
10316
10317            row_delta =
10318                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10319        }
10320
10321        self.transact(window, cx, |this, window, cx| {
10322            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10323            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10324        });
10325    }
10326
10327    fn indent_selection(
10328        buffer: &MultiBuffer,
10329        snapshot: &MultiBufferSnapshot,
10330        selection: &mut Selection<Point>,
10331        edits: &mut Vec<(Range<Point>, String)>,
10332        delta_for_start_row: u32,
10333        cx: &App,
10334    ) -> u32 {
10335        let settings = buffer.language_settings_at(selection.start, cx);
10336        let tab_size = settings.tab_size.get();
10337        let indent_kind = if settings.hard_tabs {
10338            IndentKind::Tab
10339        } else {
10340            IndentKind::Space
10341        };
10342        let mut start_row = selection.start.row;
10343        let mut end_row = selection.end.row + 1;
10344
10345        // If a selection ends at the beginning of a line, don't indent
10346        // that last line.
10347        if selection.end.column == 0 && selection.end.row > selection.start.row {
10348            end_row -= 1;
10349        }
10350
10351        // Avoid re-indenting a row that has already been indented by a
10352        // previous selection, but still update this selection's column
10353        // to reflect that indentation.
10354        if delta_for_start_row > 0 {
10355            start_row += 1;
10356            selection.start.column += delta_for_start_row;
10357            if selection.end.row == selection.start.row {
10358                selection.end.column += delta_for_start_row;
10359            }
10360        }
10361
10362        let mut delta_for_end_row = 0;
10363        let has_multiple_rows = start_row + 1 != end_row;
10364        for row in start_row..end_row {
10365            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10366            let indent_delta = match (current_indent.kind, indent_kind) {
10367                (IndentKind::Space, IndentKind::Space) => {
10368                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10369                    IndentSize::spaces(columns_to_next_tab_stop)
10370                }
10371                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10372                (_, IndentKind::Tab) => IndentSize::tab(),
10373            };
10374
10375            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10376                0
10377            } else {
10378                selection.start.column
10379            };
10380            let row_start = Point::new(row, start);
10381            edits.push((
10382                row_start..row_start,
10383                indent_delta.chars().collect::<String>(),
10384            ));
10385
10386            // Update this selection's endpoints to reflect the indentation.
10387            if row == selection.start.row {
10388                selection.start.column += indent_delta.len;
10389            }
10390            if row == selection.end.row {
10391                selection.end.column += indent_delta.len;
10392                delta_for_end_row = indent_delta.len;
10393            }
10394        }
10395
10396        if selection.start.row == selection.end.row {
10397            delta_for_start_row + delta_for_end_row
10398        } else {
10399            delta_for_end_row
10400        }
10401    }
10402
10403    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10404        if self.read_only(cx) {
10405            return;
10406        }
10407        if self.mode.is_single_line() {
10408            cx.propagate();
10409            return;
10410        }
10411
10412        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10414        let selections = self.selections.all::<Point>(&display_map);
10415        let mut deletion_ranges = Vec::new();
10416        let mut last_outdent = None;
10417        {
10418            let buffer = self.buffer.read(cx);
10419            let snapshot = buffer.snapshot(cx);
10420            for selection in &selections {
10421                let settings = buffer.language_settings_at(selection.start, cx);
10422                let tab_size = settings.tab_size.get();
10423                let mut rows = selection.spanned_rows(false, &display_map);
10424
10425                // Avoid re-outdenting a row that has already been outdented by a
10426                // previous selection.
10427                if let Some(last_row) = last_outdent
10428                    && last_row == rows.start
10429                {
10430                    rows.start = rows.start.next_row();
10431                }
10432                let has_multiple_rows = rows.len() > 1;
10433                for row in rows.iter_rows() {
10434                    let indent_size = snapshot.indent_size_for_line(row);
10435                    if indent_size.len > 0 {
10436                        let deletion_len = match indent_size.kind {
10437                            IndentKind::Space => {
10438                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10439                                if columns_to_prev_tab_stop == 0 {
10440                                    tab_size
10441                                } else {
10442                                    columns_to_prev_tab_stop
10443                                }
10444                            }
10445                            IndentKind::Tab => 1,
10446                        };
10447                        let start = if has_multiple_rows
10448                            || deletion_len > selection.start.column
10449                            || indent_size.len < selection.start.column
10450                        {
10451                            0
10452                        } else {
10453                            selection.start.column - deletion_len
10454                        };
10455                        deletion_ranges.push(
10456                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10457                        );
10458                        last_outdent = Some(row);
10459                    }
10460                }
10461            }
10462        }
10463
10464        self.transact(window, cx, |this, window, cx| {
10465            this.buffer.update(cx, |buffer, cx| {
10466                let empty_str: Arc<str> = Arc::default();
10467                buffer.edit(
10468                    deletion_ranges
10469                        .into_iter()
10470                        .map(|range| (range, empty_str.clone())),
10471                    None,
10472                    cx,
10473                );
10474            });
10475            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10476            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10477        });
10478    }
10479
10480    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10481        if self.read_only(cx) {
10482            return;
10483        }
10484        if self.mode.is_single_line() {
10485            cx.propagate();
10486            return;
10487        }
10488
10489        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10490        let selections = self
10491            .selections
10492            .all::<usize>(&self.display_snapshot(cx))
10493            .into_iter()
10494            .map(|s| s.range());
10495
10496        self.transact(window, cx, |this, window, cx| {
10497            this.buffer.update(cx, |buffer, cx| {
10498                buffer.autoindent_ranges(selections, cx);
10499            });
10500            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10501            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10502        });
10503    }
10504
10505    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10507        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10508        let selections = self.selections.all::<Point>(&display_map);
10509
10510        let mut new_cursors = Vec::new();
10511        let mut edit_ranges = Vec::new();
10512        let mut selections = selections.iter().peekable();
10513        while let Some(selection) = selections.next() {
10514            let mut rows = selection.spanned_rows(false, &display_map);
10515
10516            // Accumulate contiguous regions of rows that we want to delete.
10517            while let Some(next_selection) = selections.peek() {
10518                let next_rows = next_selection.spanned_rows(false, &display_map);
10519                if next_rows.start <= rows.end {
10520                    rows.end = next_rows.end;
10521                    selections.next().unwrap();
10522                } else {
10523                    break;
10524                }
10525            }
10526
10527            let buffer = display_map.buffer_snapshot();
10528            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10529            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10530                // If there's a line after the range, delete the \n from the end of the row range
10531                (
10532                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10533                    rows.end,
10534                )
10535            } else {
10536                // If there isn't a line after the range, delete the \n from the line before the
10537                // start of the row range
10538                edit_start = edit_start.saturating_sub(1);
10539                (buffer.len(), rows.start.previous_row())
10540            };
10541
10542            let text_layout_details = self.text_layout_details(window);
10543            let x = display_map.x_for_display_point(
10544                selection.head().to_display_point(&display_map),
10545                &text_layout_details,
10546            );
10547            let row = Point::new(target_row.0, 0)
10548                .to_display_point(&display_map)
10549                .row();
10550            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10551
10552            new_cursors.push((
10553                selection.id,
10554                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10555                SelectionGoal::None,
10556            ));
10557            edit_ranges.push(edit_start..edit_end);
10558        }
10559
10560        self.transact(window, cx, |this, window, cx| {
10561            let buffer = this.buffer.update(cx, |buffer, cx| {
10562                let empty_str: Arc<str> = Arc::default();
10563                buffer.edit(
10564                    edit_ranges
10565                        .into_iter()
10566                        .map(|range| (range, empty_str.clone())),
10567                    None,
10568                    cx,
10569                );
10570                buffer.snapshot(cx)
10571            });
10572            let new_selections = new_cursors
10573                .into_iter()
10574                .map(|(id, cursor, goal)| {
10575                    let cursor = cursor.to_point(&buffer);
10576                    Selection {
10577                        id,
10578                        start: cursor,
10579                        end: cursor,
10580                        reversed: false,
10581                        goal,
10582                    }
10583                })
10584                .collect();
10585
10586            this.change_selections(Default::default(), window, cx, |s| {
10587                s.select(new_selections);
10588            });
10589        });
10590    }
10591
10592    pub fn join_lines_impl(
10593        &mut self,
10594        insert_whitespace: bool,
10595        window: &mut Window,
10596        cx: &mut Context<Self>,
10597    ) {
10598        if self.read_only(cx) {
10599            return;
10600        }
10601        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10602        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10603            let start = MultiBufferRow(selection.start.row);
10604            // Treat single line selections as if they include the next line. Otherwise this action
10605            // would do nothing for single line selections individual cursors.
10606            let end = if selection.start.row == selection.end.row {
10607                MultiBufferRow(selection.start.row + 1)
10608            } else {
10609                MultiBufferRow(selection.end.row)
10610            };
10611
10612            if let Some(last_row_range) = row_ranges.last_mut()
10613                && start <= last_row_range.end
10614            {
10615                last_row_range.end = end;
10616                continue;
10617            }
10618            row_ranges.push(start..end);
10619        }
10620
10621        let snapshot = self.buffer.read(cx).snapshot(cx);
10622        let mut cursor_positions = Vec::new();
10623        for row_range in &row_ranges {
10624            let anchor = snapshot.anchor_before(Point::new(
10625                row_range.end.previous_row().0,
10626                snapshot.line_len(row_range.end.previous_row()),
10627            ));
10628            cursor_positions.push(anchor..anchor);
10629        }
10630
10631        self.transact(window, cx, |this, window, cx| {
10632            for row_range in row_ranges.into_iter().rev() {
10633                for row in row_range.iter_rows().rev() {
10634                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10635                    let next_line_row = row.next_row();
10636                    let indent = snapshot.indent_size_for_line(next_line_row);
10637                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10638
10639                    let replace =
10640                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10641                            " "
10642                        } else {
10643                            ""
10644                        };
10645
10646                    this.buffer.update(cx, |buffer, cx| {
10647                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10648                    });
10649                }
10650            }
10651
10652            this.change_selections(Default::default(), window, cx, |s| {
10653                s.select_anchor_ranges(cursor_positions)
10654            });
10655        });
10656    }
10657
10658    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10660        self.join_lines_impl(true, window, cx);
10661    }
10662
10663    pub fn sort_lines_case_sensitive(
10664        &mut self,
10665        _: &SortLinesCaseSensitive,
10666        window: &mut Window,
10667        cx: &mut Context<Self>,
10668    ) {
10669        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10670    }
10671
10672    pub fn sort_lines_by_length(
10673        &mut self,
10674        _: &SortLinesByLength,
10675        window: &mut Window,
10676        cx: &mut Context<Self>,
10677    ) {
10678        self.manipulate_immutable_lines(window, cx, |lines| {
10679            lines.sort_by_key(|&line| line.chars().count())
10680        })
10681    }
10682
10683    pub fn sort_lines_case_insensitive(
10684        &mut self,
10685        _: &SortLinesCaseInsensitive,
10686        window: &mut Window,
10687        cx: &mut Context<Self>,
10688    ) {
10689        self.manipulate_immutable_lines(window, cx, |lines| {
10690            lines.sort_by_key(|line| line.to_lowercase())
10691        })
10692    }
10693
10694    pub fn unique_lines_case_insensitive(
10695        &mut self,
10696        _: &UniqueLinesCaseInsensitive,
10697        window: &mut Window,
10698        cx: &mut Context<Self>,
10699    ) {
10700        self.manipulate_immutable_lines(window, cx, |lines| {
10701            let mut seen = HashSet::default();
10702            lines.retain(|line| seen.insert(line.to_lowercase()));
10703        })
10704    }
10705
10706    pub fn unique_lines_case_sensitive(
10707        &mut self,
10708        _: &UniqueLinesCaseSensitive,
10709        window: &mut Window,
10710        cx: &mut Context<Self>,
10711    ) {
10712        self.manipulate_immutable_lines(window, cx, |lines| {
10713            let mut seen = HashSet::default();
10714            lines.retain(|line| seen.insert(*line));
10715        })
10716    }
10717
10718    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10719        let snapshot = self.buffer.read(cx).snapshot(cx);
10720        for selection in self.selections.disjoint_anchors_arc().iter() {
10721            if snapshot
10722                .language_at(selection.start)
10723                .and_then(|lang| lang.config().wrap_characters.as_ref())
10724                .is_some()
10725            {
10726                return true;
10727            }
10728        }
10729        false
10730    }
10731
10732    fn wrap_selections_in_tag(
10733        &mut self,
10734        _: &WrapSelectionsInTag,
10735        window: &mut Window,
10736        cx: &mut Context<Self>,
10737    ) {
10738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10739
10740        let snapshot = self.buffer.read(cx).snapshot(cx);
10741
10742        let mut edits = Vec::new();
10743        let mut boundaries = Vec::new();
10744
10745        for selection in self
10746            .selections
10747            .all::<Point>(&self.display_snapshot(cx))
10748            .iter()
10749        {
10750            let Some(wrap_config) = snapshot
10751                .language_at(selection.start)
10752                .and_then(|lang| lang.config().wrap_characters.clone())
10753            else {
10754                continue;
10755            };
10756
10757            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10758            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10759
10760            let start_before = snapshot.anchor_before(selection.start);
10761            let end_after = snapshot.anchor_after(selection.end);
10762
10763            edits.push((start_before..start_before, open_tag));
10764            edits.push((end_after..end_after, close_tag));
10765
10766            boundaries.push((
10767                start_before,
10768                end_after,
10769                wrap_config.start_prefix.len(),
10770                wrap_config.end_suffix.len(),
10771            ));
10772        }
10773
10774        if edits.is_empty() {
10775            return;
10776        }
10777
10778        self.transact(window, cx, |this, window, cx| {
10779            let buffer = this.buffer.update(cx, |buffer, cx| {
10780                buffer.edit(edits, None, cx);
10781                buffer.snapshot(cx)
10782            });
10783
10784            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10785            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10786                boundaries.into_iter()
10787            {
10788                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10789                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10790                new_selections.push(open_offset..open_offset);
10791                new_selections.push(close_offset..close_offset);
10792            }
10793
10794            this.change_selections(Default::default(), window, cx, |s| {
10795                s.select_ranges(new_selections);
10796            });
10797
10798            this.request_autoscroll(Autoscroll::fit(), cx);
10799        });
10800    }
10801
10802    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10803        let Some(project) = self.project.clone() else {
10804            return;
10805        };
10806        self.reload(project, window, cx)
10807            .detach_and_notify_err(window, cx);
10808    }
10809
10810    pub fn restore_file(
10811        &mut self,
10812        _: &::git::RestoreFile,
10813        window: &mut Window,
10814        cx: &mut Context<Self>,
10815    ) {
10816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10817        let mut buffer_ids = HashSet::default();
10818        let snapshot = self.buffer().read(cx).snapshot(cx);
10819        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10820            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10821        }
10822
10823        let buffer = self.buffer().read(cx);
10824        let ranges = buffer_ids
10825            .into_iter()
10826            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10827            .collect::<Vec<_>>();
10828
10829        self.restore_hunks_in_ranges(ranges, window, cx);
10830    }
10831
10832    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10834        let selections = self
10835            .selections
10836            .all(&self.display_snapshot(cx))
10837            .into_iter()
10838            .map(|s| s.range())
10839            .collect();
10840        self.restore_hunks_in_ranges(selections, window, cx);
10841    }
10842
10843    pub fn restore_hunks_in_ranges(
10844        &mut self,
10845        ranges: Vec<Range<Point>>,
10846        window: &mut Window,
10847        cx: &mut Context<Editor>,
10848    ) {
10849        let mut revert_changes = HashMap::default();
10850        let chunk_by = self
10851            .snapshot(window, cx)
10852            .hunks_for_ranges(ranges)
10853            .into_iter()
10854            .chunk_by(|hunk| hunk.buffer_id);
10855        for (buffer_id, hunks) in &chunk_by {
10856            let hunks = hunks.collect::<Vec<_>>();
10857            for hunk in &hunks {
10858                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10859            }
10860            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10861        }
10862        drop(chunk_by);
10863        if !revert_changes.is_empty() {
10864            self.transact(window, cx, |editor, window, cx| {
10865                editor.restore(revert_changes, window, cx);
10866            });
10867        }
10868    }
10869
10870    pub fn open_active_item_in_terminal(
10871        &mut self,
10872        _: &OpenInTerminal,
10873        window: &mut Window,
10874        cx: &mut Context<Self>,
10875    ) {
10876        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10877            let project_path = buffer.read(cx).project_path(cx)?;
10878            let project = self.project()?.read(cx);
10879            let entry = project.entry_for_path(&project_path, cx)?;
10880            let parent = match &entry.canonical_path {
10881                Some(canonical_path) => canonical_path.to_path_buf(),
10882                None => project.absolute_path(&project_path, cx)?,
10883            }
10884            .parent()?
10885            .to_path_buf();
10886            Some(parent)
10887        }) {
10888            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10889        }
10890    }
10891
10892    fn set_breakpoint_context_menu(
10893        &mut self,
10894        display_row: DisplayRow,
10895        position: Option<Anchor>,
10896        clicked_point: gpui::Point<Pixels>,
10897        window: &mut Window,
10898        cx: &mut Context<Self>,
10899    ) {
10900        let source = self
10901            .buffer
10902            .read(cx)
10903            .snapshot(cx)
10904            .anchor_before(Point::new(display_row.0, 0u32));
10905
10906        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10907
10908        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10909            self,
10910            source,
10911            clicked_point,
10912            context_menu,
10913            window,
10914            cx,
10915        );
10916    }
10917
10918    fn add_edit_breakpoint_block(
10919        &mut self,
10920        anchor: Anchor,
10921        breakpoint: &Breakpoint,
10922        edit_action: BreakpointPromptEditAction,
10923        window: &mut Window,
10924        cx: &mut Context<Self>,
10925    ) {
10926        let weak_editor = cx.weak_entity();
10927        let bp_prompt = cx.new(|cx| {
10928            BreakpointPromptEditor::new(
10929                weak_editor,
10930                anchor,
10931                breakpoint.clone(),
10932                edit_action,
10933                window,
10934                cx,
10935            )
10936        });
10937
10938        let height = bp_prompt.update(cx, |this, cx| {
10939            this.prompt
10940                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10941        });
10942        let cloned_prompt = bp_prompt.clone();
10943        let blocks = vec![BlockProperties {
10944            style: BlockStyle::Sticky,
10945            placement: BlockPlacement::Above(anchor),
10946            height: Some(height),
10947            render: Arc::new(move |cx| {
10948                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10949                cloned_prompt.clone().into_any_element()
10950            }),
10951            priority: 0,
10952        }];
10953
10954        let focus_handle = bp_prompt.focus_handle(cx);
10955        window.focus(&focus_handle);
10956
10957        let block_ids = self.insert_blocks(blocks, None, cx);
10958        bp_prompt.update(cx, |prompt, _| {
10959            prompt.add_block_ids(block_ids);
10960        });
10961    }
10962
10963    pub(crate) fn breakpoint_at_row(
10964        &self,
10965        row: u32,
10966        window: &mut Window,
10967        cx: &mut Context<Self>,
10968    ) -> Option<(Anchor, Breakpoint)> {
10969        let snapshot = self.snapshot(window, cx);
10970        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10971
10972        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10973    }
10974
10975    pub(crate) fn breakpoint_at_anchor(
10976        &self,
10977        breakpoint_position: Anchor,
10978        snapshot: &EditorSnapshot,
10979        cx: &mut Context<Self>,
10980    ) -> Option<(Anchor, Breakpoint)> {
10981        let buffer = self
10982            .buffer
10983            .read(cx)
10984            .buffer_for_anchor(breakpoint_position, cx)?;
10985
10986        let enclosing_excerpt = breakpoint_position.excerpt_id;
10987        let buffer_snapshot = buffer.read(cx).snapshot();
10988
10989        let row = buffer_snapshot
10990            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10991            .row;
10992
10993        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10994        let anchor_end = snapshot
10995            .buffer_snapshot()
10996            .anchor_after(Point::new(row, line_len));
10997
10998        self.breakpoint_store
10999            .as_ref()?
11000            .read_with(cx, |breakpoint_store, cx| {
11001                breakpoint_store
11002                    .breakpoints(
11003                        &buffer,
11004                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11005                        &buffer_snapshot,
11006                        cx,
11007                    )
11008                    .next()
11009                    .and_then(|(bp, _)| {
11010                        let breakpoint_row = buffer_snapshot
11011                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11012                            .row;
11013
11014                        if breakpoint_row == row {
11015                            snapshot
11016                                .buffer_snapshot()
11017                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11018                                .map(|position| (position, bp.bp.clone()))
11019                        } else {
11020                            None
11021                        }
11022                    })
11023            })
11024    }
11025
11026    pub fn edit_log_breakpoint(
11027        &mut self,
11028        _: &EditLogBreakpoint,
11029        window: &mut Window,
11030        cx: &mut Context<Self>,
11031    ) {
11032        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11033            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11034                message: None,
11035                state: BreakpointState::Enabled,
11036                condition: None,
11037                hit_condition: None,
11038            });
11039
11040            self.add_edit_breakpoint_block(
11041                anchor,
11042                &breakpoint,
11043                BreakpointPromptEditAction::Log,
11044                window,
11045                cx,
11046            );
11047        }
11048    }
11049
11050    fn breakpoints_at_cursors(
11051        &self,
11052        window: &mut Window,
11053        cx: &mut Context<Self>,
11054    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11055        let snapshot = self.snapshot(window, cx);
11056        let cursors = self
11057            .selections
11058            .disjoint_anchors_arc()
11059            .iter()
11060            .map(|selection| {
11061                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11062
11063                let breakpoint_position = self
11064                    .breakpoint_at_row(cursor_position.row, window, cx)
11065                    .map(|bp| bp.0)
11066                    .unwrap_or_else(|| {
11067                        snapshot
11068                            .display_snapshot
11069                            .buffer_snapshot()
11070                            .anchor_after(Point::new(cursor_position.row, 0))
11071                    });
11072
11073                let breakpoint = self
11074                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11075                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11076
11077                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11078            })
11079            // 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.
11080            .collect::<HashMap<Anchor, _>>();
11081
11082        cursors.into_iter().collect()
11083    }
11084
11085    pub fn enable_breakpoint(
11086        &mut self,
11087        _: &crate::actions::EnableBreakpoint,
11088        window: &mut Window,
11089        cx: &mut Context<Self>,
11090    ) {
11091        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11092            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11093                continue;
11094            };
11095            self.edit_breakpoint_at_anchor(
11096                anchor,
11097                breakpoint,
11098                BreakpointEditAction::InvertState,
11099                cx,
11100            );
11101        }
11102    }
11103
11104    pub fn disable_breakpoint(
11105        &mut self,
11106        _: &crate::actions::DisableBreakpoint,
11107        window: &mut Window,
11108        cx: &mut Context<Self>,
11109    ) {
11110        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11111            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11112                continue;
11113            };
11114            self.edit_breakpoint_at_anchor(
11115                anchor,
11116                breakpoint,
11117                BreakpointEditAction::InvertState,
11118                cx,
11119            );
11120        }
11121    }
11122
11123    pub fn toggle_breakpoint(
11124        &mut self,
11125        _: &crate::actions::ToggleBreakpoint,
11126        window: &mut Window,
11127        cx: &mut Context<Self>,
11128    ) {
11129        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11130            if let Some(breakpoint) = breakpoint {
11131                self.edit_breakpoint_at_anchor(
11132                    anchor,
11133                    breakpoint,
11134                    BreakpointEditAction::Toggle,
11135                    cx,
11136                );
11137            } else {
11138                self.edit_breakpoint_at_anchor(
11139                    anchor,
11140                    Breakpoint::new_standard(),
11141                    BreakpointEditAction::Toggle,
11142                    cx,
11143                );
11144            }
11145        }
11146    }
11147
11148    pub fn edit_breakpoint_at_anchor(
11149        &mut self,
11150        breakpoint_position: Anchor,
11151        breakpoint: Breakpoint,
11152        edit_action: BreakpointEditAction,
11153        cx: &mut Context<Self>,
11154    ) {
11155        let Some(breakpoint_store) = &self.breakpoint_store else {
11156            return;
11157        };
11158
11159        let Some(buffer) = self
11160            .buffer
11161            .read(cx)
11162            .buffer_for_anchor(breakpoint_position, cx)
11163        else {
11164            return;
11165        };
11166
11167        breakpoint_store.update(cx, |breakpoint_store, cx| {
11168            breakpoint_store.toggle_breakpoint(
11169                buffer,
11170                BreakpointWithPosition {
11171                    position: breakpoint_position.text_anchor,
11172                    bp: breakpoint,
11173                },
11174                edit_action,
11175                cx,
11176            );
11177        });
11178
11179        cx.notify();
11180    }
11181
11182    #[cfg(any(test, feature = "test-support"))]
11183    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11184        self.breakpoint_store.clone()
11185    }
11186
11187    pub fn prepare_restore_change(
11188        &self,
11189        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11190        hunk: &MultiBufferDiffHunk,
11191        cx: &mut App,
11192    ) -> Option<()> {
11193        if hunk.is_created_file() {
11194            return None;
11195        }
11196        let buffer = self.buffer.read(cx);
11197        let diff = buffer.diff_for(hunk.buffer_id)?;
11198        let buffer = buffer.buffer(hunk.buffer_id)?;
11199        let buffer = buffer.read(cx);
11200        let original_text = diff
11201            .read(cx)
11202            .base_text()
11203            .as_rope()
11204            .slice(hunk.diff_base_byte_range.clone());
11205        let buffer_snapshot = buffer.snapshot();
11206        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11207        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11208            probe
11209                .0
11210                .start
11211                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11212                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11213        }) {
11214            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11215            Some(())
11216        } else {
11217            None
11218        }
11219    }
11220
11221    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11222        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11223    }
11224
11225    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11226        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11227    }
11228
11229    fn manipulate_lines<M>(
11230        &mut self,
11231        window: &mut Window,
11232        cx: &mut Context<Self>,
11233        mut manipulate: M,
11234    ) where
11235        M: FnMut(&str) -> LineManipulationResult,
11236    {
11237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11238
11239        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11240        let buffer = self.buffer.read(cx).snapshot(cx);
11241
11242        let mut edits = Vec::new();
11243
11244        let selections = self.selections.all::<Point>(&display_map);
11245        let mut selections = selections.iter().peekable();
11246        let mut contiguous_row_selections = Vec::new();
11247        let mut new_selections = Vec::new();
11248        let mut added_lines = 0;
11249        let mut removed_lines = 0;
11250
11251        while let Some(selection) = selections.next() {
11252            let (start_row, end_row) = consume_contiguous_rows(
11253                &mut contiguous_row_selections,
11254                selection,
11255                &display_map,
11256                &mut selections,
11257            );
11258
11259            let start_point = Point::new(start_row.0, 0);
11260            let end_point = Point::new(
11261                end_row.previous_row().0,
11262                buffer.line_len(end_row.previous_row()),
11263            );
11264            let text = buffer
11265                .text_for_range(start_point..end_point)
11266                .collect::<String>();
11267
11268            let LineManipulationResult {
11269                new_text,
11270                line_count_before,
11271                line_count_after,
11272            } = manipulate(&text);
11273
11274            edits.push((start_point..end_point, new_text));
11275
11276            // Selections must change based on added and removed line count
11277            let start_row =
11278                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11279            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11280            new_selections.push(Selection {
11281                id: selection.id,
11282                start: start_row,
11283                end: end_row,
11284                goal: SelectionGoal::None,
11285                reversed: selection.reversed,
11286            });
11287
11288            if line_count_after > line_count_before {
11289                added_lines += line_count_after - line_count_before;
11290            } else if line_count_before > line_count_after {
11291                removed_lines += line_count_before - line_count_after;
11292            }
11293        }
11294
11295        self.transact(window, cx, |this, window, cx| {
11296            let buffer = this.buffer.update(cx, |buffer, cx| {
11297                buffer.edit(edits, None, cx);
11298                buffer.snapshot(cx)
11299            });
11300
11301            // Recalculate offsets on newly edited buffer
11302            let new_selections = new_selections
11303                .iter()
11304                .map(|s| {
11305                    let start_point = Point::new(s.start.0, 0);
11306                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11307                    Selection {
11308                        id: s.id,
11309                        start: buffer.point_to_offset(start_point),
11310                        end: buffer.point_to_offset(end_point),
11311                        goal: s.goal,
11312                        reversed: s.reversed,
11313                    }
11314                })
11315                .collect();
11316
11317            this.change_selections(Default::default(), window, cx, |s| {
11318                s.select(new_selections);
11319            });
11320
11321            this.request_autoscroll(Autoscroll::fit(), cx);
11322        });
11323    }
11324
11325    fn manipulate_immutable_lines<Fn>(
11326        &mut self,
11327        window: &mut Window,
11328        cx: &mut Context<Self>,
11329        mut callback: Fn,
11330    ) where
11331        Fn: FnMut(&mut Vec<&str>),
11332    {
11333        self.manipulate_lines(window, cx, |text| {
11334            let mut lines: Vec<&str> = text.split('\n').collect();
11335            let line_count_before = lines.len();
11336
11337            callback(&mut lines);
11338
11339            LineManipulationResult {
11340                new_text: lines.join("\n"),
11341                line_count_before,
11342                line_count_after: lines.len(),
11343            }
11344        });
11345    }
11346
11347    fn manipulate_mutable_lines<Fn>(
11348        &mut self,
11349        window: &mut Window,
11350        cx: &mut Context<Self>,
11351        mut callback: Fn,
11352    ) where
11353        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11354    {
11355        self.manipulate_lines(window, cx, |text| {
11356            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11357            let line_count_before = lines.len();
11358
11359            callback(&mut lines);
11360
11361            LineManipulationResult {
11362                new_text: lines.join("\n"),
11363                line_count_before,
11364                line_count_after: lines.len(),
11365            }
11366        });
11367    }
11368
11369    pub fn convert_indentation_to_spaces(
11370        &mut self,
11371        _: &ConvertIndentationToSpaces,
11372        window: &mut Window,
11373        cx: &mut Context<Self>,
11374    ) {
11375        let settings = self.buffer.read(cx).language_settings(cx);
11376        let tab_size = settings.tab_size.get() as usize;
11377
11378        self.manipulate_mutable_lines(window, cx, |lines| {
11379            // Allocates a reasonably sized scratch buffer once for the whole loop
11380            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11381            // Avoids recomputing spaces that could be inserted many times
11382            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11383                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11384                .collect();
11385
11386            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11387                let mut chars = line.as_ref().chars();
11388                let mut col = 0;
11389                let mut changed = false;
11390
11391                for ch in chars.by_ref() {
11392                    match ch {
11393                        ' ' => {
11394                            reindented_line.push(' ');
11395                            col += 1;
11396                        }
11397                        '\t' => {
11398                            // \t are converted to spaces depending on the current column
11399                            let spaces_len = tab_size - (col % tab_size);
11400                            reindented_line.extend(&space_cache[spaces_len - 1]);
11401                            col += spaces_len;
11402                            changed = true;
11403                        }
11404                        _ => {
11405                            // If we dont append before break, the character is consumed
11406                            reindented_line.push(ch);
11407                            break;
11408                        }
11409                    }
11410                }
11411
11412                if !changed {
11413                    reindented_line.clear();
11414                    continue;
11415                }
11416                // Append the rest of the line and replace old reference with new one
11417                reindented_line.extend(chars);
11418                *line = Cow::Owned(reindented_line.clone());
11419                reindented_line.clear();
11420            }
11421        });
11422    }
11423
11424    pub fn convert_indentation_to_tabs(
11425        &mut self,
11426        _: &ConvertIndentationToTabs,
11427        window: &mut Window,
11428        cx: &mut Context<Self>,
11429    ) {
11430        let settings = self.buffer.read(cx).language_settings(cx);
11431        let tab_size = settings.tab_size.get() as usize;
11432
11433        self.manipulate_mutable_lines(window, cx, |lines| {
11434            // Allocates a reasonably sized buffer once for the whole loop
11435            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11436            // Avoids recomputing spaces that could be inserted many times
11437            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11438                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11439                .collect();
11440
11441            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11442                let mut chars = line.chars();
11443                let mut spaces_count = 0;
11444                let mut first_non_indent_char = None;
11445                let mut changed = false;
11446
11447                for ch in chars.by_ref() {
11448                    match ch {
11449                        ' ' => {
11450                            // Keep track of spaces. Append \t when we reach tab_size
11451                            spaces_count += 1;
11452                            changed = true;
11453                            if spaces_count == tab_size {
11454                                reindented_line.push('\t');
11455                                spaces_count = 0;
11456                            }
11457                        }
11458                        '\t' => {
11459                            reindented_line.push('\t');
11460                            spaces_count = 0;
11461                        }
11462                        _ => {
11463                            // Dont append it yet, we might have remaining spaces
11464                            first_non_indent_char = Some(ch);
11465                            break;
11466                        }
11467                    }
11468                }
11469
11470                if !changed {
11471                    reindented_line.clear();
11472                    continue;
11473                }
11474                // Remaining spaces that didn't make a full tab stop
11475                if spaces_count > 0 {
11476                    reindented_line.extend(&space_cache[spaces_count - 1]);
11477                }
11478                // If we consume an extra character that was not indentation, add it back
11479                if let Some(extra_char) = first_non_indent_char {
11480                    reindented_line.push(extra_char);
11481                }
11482                // Append the rest of the line and replace old reference with new one
11483                reindented_line.extend(chars);
11484                *line = Cow::Owned(reindented_line.clone());
11485                reindented_line.clear();
11486            }
11487        });
11488    }
11489
11490    pub fn convert_to_upper_case(
11491        &mut self,
11492        _: &ConvertToUpperCase,
11493        window: &mut Window,
11494        cx: &mut Context<Self>,
11495    ) {
11496        self.manipulate_text(window, cx, |text| text.to_uppercase())
11497    }
11498
11499    pub fn convert_to_lower_case(
11500        &mut self,
11501        _: &ConvertToLowerCase,
11502        window: &mut Window,
11503        cx: &mut Context<Self>,
11504    ) {
11505        self.manipulate_text(window, cx, |text| text.to_lowercase())
11506    }
11507
11508    pub fn convert_to_title_case(
11509        &mut self,
11510        _: &ConvertToTitleCase,
11511        window: &mut Window,
11512        cx: &mut Context<Self>,
11513    ) {
11514        self.manipulate_text(window, cx, |text| {
11515            text.split('\n')
11516                .map(|line| line.to_case(Case::Title))
11517                .join("\n")
11518        })
11519    }
11520
11521    pub fn convert_to_snake_case(
11522        &mut self,
11523        _: &ConvertToSnakeCase,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11528    }
11529
11530    pub fn convert_to_kebab_case(
11531        &mut self,
11532        _: &ConvertToKebabCase,
11533        window: &mut Window,
11534        cx: &mut Context<Self>,
11535    ) {
11536        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11537    }
11538
11539    pub fn convert_to_upper_camel_case(
11540        &mut self,
11541        _: &ConvertToUpperCamelCase,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544    ) {
11545        self.manipulate_text(window, cx, |text| {
11546            text.split('\n')
11547                .map(|line| line.to_case(Case::UpperCamel))
11548                .join("\n")
11549        })
11550    }
11551
11552    pub fn convert_to_lower_camel_case(
11553        &mut self,
11554        _: &ConvertToLowerCamelCase,
11555        window: &mut Window,
11556        cx: &mut Context<Self>,
11557    ) {
11558        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11559    }
11560
11561    pub fn convert_to_opposite_case(
11562        &mut self,
11563        _: &ConvertToOppositeCase,
11564        window: &mut Window,
11565        cx: &mut Context<Self>,
11566    ) {
11567        self.manipulate_text(window, cx, |text| {
11568            text.chars()
11569                .fold(String::with_capacity(text.len()), |mut t, c| {
11570                    if c.is_uppercase() {
11571                        t.extend(c.to_lowercase());
11572                    } else {
11573                        t.extend(c.to_uppercase());
11574                    }
11575                    t
11576                })
11577        })
11578    }
11579
11580    pub fn convert_to_sentence_case(
11581        &mut self,
11582        _: &ConvertToSentenceCase,
11583        window: &mut Window,
11584        cx: &mut Context<Self>,
11585    ) {
11586        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11587    }
11588
11589    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11590        self.manipulate_text(window, cx, |text| {
11591            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11592            if has_upper_case_characters {
11593                text.to_lowercase()
11594            } else {
11595                text.to_uppercase()
11596            }
11597        })
11598    }
11599
11600    pub fn convert_to_rot13(
11601        &mut self,
11602        _: &ConvertToRot13,
11603        window: &mut Window,
11604        cx: &mut Context<Self>,
11605    ) {
11606        self.manipulate_text(window, cx, |text| {
11607            text.chars()
11608                .map(|c| match c {
11609                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11610                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11611                    _ => c,
11612                })
11613                .collect()
11614        })
11615    }
11616
11617    pub fn convert_to_rot47(
11618        &mut self,
11619        _: &ConvertToRot47,
11620        window: &mut Window,
11621        cx: &mut Context<Self>,
11622    ) {
11623        self.manipulate_text(window, cx, |text| {
11624            text.chars()
11625                .map(|c| {
11626                    let code_point = c as u32;
11627                    if code_point >= 33 && code_point <= 126 {
11628                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11629                    }
11630                    c
11631                })
11632                .collect()
11633        })
11634    }
11635
11636    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11637    where
11638        Fn: FnMut(&str) -> String,
11639    {
11640        let buffer = self.buffer.read(cx).snapshot(cx);
11641
11642        let mut new_selections = Vec::new();
11643        let mut edits = Vec::new();
11644        let mut selection_adjustment = 0i32;
11645
11646        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11647            let selection_is_empty = selection.is_empty();
11648
11649            let (start, end) = if selection_is_empty {
11650                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11651                (word_range.start, word_range.end)
11652            } else {
11653                (
11654                    buffer.point_to_offset(selection.start),
11655                    buffer.point_to_offset(selection.end),
11656                )
11657            };
11658
11659            let text = buffer.text_for_range(start..end).collect::<String>();
11660            let old_length = text.len() as i32;
11661            let text = callback(&text);
11662
11663            new_selections.push(Selection {
11664                start: (start as i32 - selection_adjustment) as usize,
11665                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11666                goal: SelectionGoal::None,
11667                id: selection.id,
11668                reversed: selection.reversed,
11669            });
11670
11671            selection_adjustment += old_length - text.len() as i32;
11672
11673            edits.push((start..end, text));
11674        }
11675
11676        self.transact(window, cx, |this, window, cx| {
11677            this.buffer.update(cx, |buffer, cx| {
11678                buffer.edit(edits, None, cx);
11679            });
11680
11681            this.change_selections(Default::default(), window, cx, |s| {
11682                s.select(new_selections);
11683            });
11684
11685            this.request_autoscroll(Autoscroll::fit(), cx);
11686        });
11687    }
11688
11689    pub fn move_selection_on_drop(
11690        &mut self,
11691        selection: &Selection<Anchor>,
11692        target: DisplayPoint,
11693        is_cut: bool,
11694        window: &mut Window,
11695        cx: &mut Context<Self>,
11696    ) {
11697        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11698        let buffer = display_map.buffer_snapshot();
11699        let mut edits = Vec::new();
11700        let insert_point = display_map
11701            .clip_point(target, Bias::Left)
11702            .to_point(&display_map);
11703        let text = buffer
11704            .text_for_range(selection.start..selection.end)
11705            .collect::<String>();
11706        if is_cut {
11707            edits.push(((selection.start..selection.end), String::new()));
11708        }
11709        let insert_anchor = buffer.anchor_before(insert_point);
11710        edits.push(((insert_anchor..insert_anchor), text));
11711        let last_edit_start = insert_anchor.bias_left(buffer);
11712        let last_edit_end = insert_anchor.bias_right(buffer);
11713        self.transact(window, cx, |this, window, cx| {
11714            this.buffer.update(cx, |buffer, cx| {
11715                buffer.edit(edits, None, cx);
11716            });
11717            this.change_selections(Default::default(), window, cx, |s| {
11718                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11719            });
11720        });
11721    }
11722
11723    pub fn clear_selection_drag_state(&mut self) {
11724        self.selection_drag_state = SelectionDragState::None;
11725    }
11726
11727    pub fn duplicate(
11728        &mut self,
11729        upwards: bool,
11730        whole_lines: bool,
11731        window: &mut Window,
11732        cx: &mut Context<Self>,
11733    ) {
11734        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11735
11736        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11737        let buffer = display_map.buffer_snapshot();
11738        let selections = self.selections.all::<Point>(&display_map);
11739
11740        let mut edits = Vec::new();
11741        let mut selections_iter = selections.iter().peekable();
11742        while let Some(selection) = selections_iter.next() {
11743            let mut rows = selection.spanned_rows(false, &display_map);
11744            // duplicate line-wise
11745            if whole_lines || selection.start == selection.end {
11746                // Avoid duplicating the same lines twice.
11747                while let Some(next_selection) = selections_iter.peek() {
11748                    let next_rows = next_selection.spanned_rows(false, &display_map);
11749                    if next_rows.start < rows.end {
11750                        rows.end = next_rows.end;
11751                        selections_iter.next().unwrap();
11752                    } else {
11753                        break;
11754                    }
11755                }
11756
11757                // Copy the text from the selected row region and splice it either at the start
11758                // or end of the region.
11759                let start = Point::new(rows.start.0, 0);
11760                let end = Point::new(
11761                    rows.end.previous_row().0,
11762                    buffer.line_len(rows.end.previous_row()),
11763                );
11764
11765                let mut text = buffer.text_for_range(start..end).collect::<String>();
11766
11767                let insert_location = if upwards {
11768                    // When duplicating upward, we need to insert before the current line.
11769                    // If we're on the last line and it doesn't end with a newline,
11770                    // we need to add a newline before the duplicated content.
11771                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11772                        && buffer.max_point().column > 0
11773                        && !text.ends_with('\n');
11774
11775                    if needs_leading_newline {
11776                        text.insert(0, '\n');
11777                        end
11778                    } else {
11779                        text.push('\n');
11780                        Point::new(rows.end.0, 0)
11781                    }
11782                } else {
11783                    text.push('\n');
11784                    start
11785                };
11786                edits.push((insert_location..insert_location, text));
11787            } else {
11788                // duplicate character-wise
11789                let start = selection.start;
11790                let end = selection.end;
11791                let text = buffer.text_for_range(start..end).collect::<String>();
11792                edits.push((selection.end..selection.end, text));
11793            }
11794        }
11795
11796        self.transact(window, cx, |this, _, cx| {
11797            this.buffer.update(cx, |buffer, cx| {
11798                buffer.edit(edits, None, cx);
11799            });
11800
11801            this.request_autoscroll(Autoscroll::fit(), cx);
11802        });
11803    }
11804
11805    pub fn duplicate_line_up(
11806        &mut self,
11807        _: &DuplicateLineUp,
11808        window: &mut Window,
11809        cx: &mut Context<Self>,
11810    ) {
11811        self.duplicate(true, true, window, cx);
11812    }
11813
11814    pub fn duplicate_line_down(
11815        &mut self,
11816        _: &DuplicateLineDown,
11817        window: &mut Window,
11818        cx: &mut Context<Self>,
11819    ) {
11820        self.duplicate(false, true, window, cx);
11821    }
11822
11823    pub fn duplicate_selection(
11824        &mut self,
11825        _: &DuplicateSelection,
11826        window: &mut Window,
11827        cx: &mut Context<Self>,
11828    ) {
11829        self.duplicate(false, false, window, cx);
11830    }
11831
11832    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11834        if self.mode.is_single_line() {
11835            cx.propagate();
11836            return;
11837        }
11838
11839        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11840        let buffer = self.buffer.read(cx).snapshot(cx);
11841
11842        let mut edits = Vec::new();
11843        let mut unfold_ranges = Vec::new();
11844        let mut refold_creases = Vec::new();
11845
11846        let selections = self.selections.all::<Point>(&display_map);
11847        let mut selections = selections.iter().peekable();
11848        let mut contiguous_row_selections = Vec::new();
11849        let mut new_selections = Vec::new();
11850
11851        while let Some(selection) = selections.next() {
11852            // Find all the selections that span a contiguous row range
11853            let (start_row, end_row) = consume_contiguous_rows(
11854                &mut contiguous_row_selections,
11855                selection,
11856                &display_map,
11857                &mut selections,
11858            );
11859
11860            // Move the text spanned by the row range to be before the line preceding the row range
11861            if start_row.0 > 0 {
11862                let range_to_move = Point::new(
11863                    start_row.previous_row().0,
11864                    buffer.line_len(start_row.previous_row()),
11865                )
11866                    ..Point::new(
11867                        end_row.previous_row().0,
11868                        buffer.line_len(end_row.previous_row()),
11869                    );
11870                let insertion_point = display_map
11871                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11872                    .0;
11873
11874                // Don't move lines across excerpts
11875                if buffer
11876                    .excerpt_containing(insertion_point..range_to_move.end)
11877                    .is_some()
11878                {
11879                    let text = buffer
11880                        .text_for_range(range_to_move.clone())
11881                        .flat_map(|s| s.chars())
11882                        .skip(1)
11883                        .chain(['\n'])
11884                        .collect::<String>();
11885
11886                    edits.push((
11887                        buffer.anchor_after(range_to_move.start)
11888                            ..buffer.anchor_before(range_to_move.end),
11889                        String::new(),
11890                    ));
11891                    let insertion_anchor = buffer.anchor_after(insertion_point);
11892                    edits.push((insertion_anchor..insertion_anchor, text));
11893
11894                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11895
11896                    // Move selections up
11897                    new_selections.extend(contiguous_row_selections.drain(..).map(
11898                        |mut selection| {
11899                            selection.start.row -= row_delta;
11900                            selection.end.row -= row_delta;
11901                            selection
11902                        },
11903                    ));
11904
11905                    // Move folds up
11906                    unfold_ranges.push(range_to_move.clone());
11907                    for fold in display_map.folds_in_range(
11908                        buffer.anchor_before(range_to_move.start)
11909                            ..buffer.anchor_after(range_to_move.end),
11910                    ) {
11911                        let mut start = fold.range.start.to_point(&buffer);
11912                        let mut end = fold.range.end.to_point(&buffer);
11913                        start.row -= row_delta;
11914                        end.row -= row_delta;
11915                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11916                    }
11917                }
11918            }
11919
11920            // If we didn't move line(s), preserve the existing selections
11921            new_selections.append(&mut contiguous_row_selections);
11922        }
11923
11924        self.transact(window, cx, |this, window, cx| {
11925            this.unfold_ranges(&unfold_ranges, true, true, cx);
11926            this.buffer.update(cx, |buffer, cx| {
11927                for (range, text) in edits {
11928                    buffer.edit([(range, text)], None, cx);
11929                }
11930            });
11931            this.fold_creases(refold_creases, true, window, cx);
11932            this.change_selections(Default::default(), window, cx, |s| {
11933                s.select(new_selections);
11934            })
11935        });
11936    }
11937
11938    pub fn move_line_down(
11939        &mut self,
11940        _: &MoveLineDown,
11941        window: &mut Window,
11942        cx: &mut Context<Self>,
11943    ) {
11944        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11945        if self.mode.is_single_line() {
11946            cx.propagate();
11947            return;
11948        }
11949
11950        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11951        let buffer = self.buffer.read(cx).snapshot(cx);
11952
11953        let mut edits = Vec::new();
11954        let mut unfold_ranges = Vec::new();
11955        let mut refold_creases = Vec::new();
11956
11957        let selections = self.selections.all::<Point>(&display_map);
11958        let mut selections = selections.iter().peekable();
11959        let mut contiguous_row_selections = Vec::new();
11960        let mut new_selections = Vec::new();
11961
11962        while let Some(selection) = selections.next() {
11963            // Find all the selections that span a contiguous row range
11964            let (start_row, end_row) = consume_contiguous_rows(
11965                &mut contiguous_row_selections,
11966                selection,
11967                &display_map,
11968                &mut selections,
11969            );
11970
11971            // Move the text spanned by the row range to be after the last line of the row range
11972            if end_row.0 <= buffer.max_point().row {
11973                let range_to_move =
11974                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11975                let insertion_point = display_map
11976                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11977                    .0;
11978
11979                // Don't move lines across excerpt boundaries
11980                if buffer
11981                    .excerpt_containing(range_to_move.start..insertion_point)
11982                    .is_some()
11983                {
11984                    let mut text = String::from("\n");
11985                    text.extend(buffer.text_for_range(range_to_move.clone()));
11986                    text.pop(); // Drop trailing newline
11987                    edits.push((
11988                        buffer.anchor_after(range_to_move.start)
11989                            ..buffer.anchor_before(range_to_move.end),
11990                        String::new(),
11991                    ));
11992                    let insertion_anchor = buffer.anchor_after(insertion_point);
11993                    edits.push((insertion_anchor..insertion_anchor, text));
11994
11995                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11996
11997                    // Move selections down
11998                    new_selections.extend(contiguous_row_selections.drain(..).map(
11999                        |mut selection| {
12000                            selection.start.row += row_delta;
12001                            selection.end.row += row_delta;
12002                            selection
12003                        },
12004                    ));
12005
12006                    // Move folds down
12007                    unfold_ranges.push(range_to_move.clone());
12008                    for fold in display_map.folds_in_range(
12009                        buffer.anchor_before(range_to_move.start)
12010                            ..buffer.anchor_after(range_to_move.end),
12011                    ) {
12012                        let mut start = fold.range.start.to_point(&buffer);
12013                        let mut end = fold.range.end.to_point(&buffer);
12014                        start.row += row_delta;
12015                        end.row += row_delta;
12016                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12017                    }
12018                }
12019            }
12020
12021            // If we didn't move line(s), preserve the existing selections
12022            new_selections.append(&mut contiguous_row_selections);
12023        }
12024
12025        self.transact(window, cx, |this, window, cx| {
12026            this.unfold_ranges(&unfold_ranges, true, true, cx);
12027            this.buffer.update(cx, |buffer, cx| {
12028                for (range, text) in edits {
12029                    buffer.edit([(range, text)], None, cx);
12030                }
12031            });
12032            this.fold_creases(refold_creases, true, window, cx);
12033            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12034        });
12035    }
12036
12037    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12038        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12039        let text_layout_details = &self.text_layout_details(window);
12040        self.transact(window, cx, |this, window, cx| {
12041            let edits = this.change_selections(Default::default(), window, cx, |s| {
12042                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12043                s.move_with(|display_map, selection| {
12044                    if !selection.is_empty() {
12045                        return;
12046                    }
12047
12048                    let mut head = selection.head();
12049                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12050                    if head.column() == display_map.line_len(head.row()) {
12051                        transpose_offset = display_map
12052                            .buffer_snapshot()
12053                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12054                    }
12055
12056                    if transpose_offset == 0 {
12057                        return;
12058                    }
12059
12060                    *head.column_mut() += 1;
12061                    head = display_map.clip_point(head, Bias::Right);
12062                    let goal = SelectionGoal::HorizontalPosition(
12063                        display_map
12064                            .x_for_display_point(head, text_layout_details)
12065                            .into(),
12066                    );
12067                    selection.collapse_to(head, goal);
12068
12069                    let transpose_start = display_map
12070                        .buffer_snapshot()
12071                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12072                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12073                        let transpose_end = display_map
12074                            .buffer_snapshot()
12075                            .clip_offset(transpose_offset + 1, Bias::Right);
12076                        if let Some(ch) = display_map
12077                            .buffer_snapshot()
12078                            .chars_at(transpose_start)
12079                            .next()
12080                        {
12081                            edits.push((transpose_start..transpose_offset, String::new()));
12082                            edits.push((transpose_end..transpose_end, ch.to_string()));
12083                        }
12084                    }
12085                });
12086                edits
12087            });
12088            this.buffer
12089                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12090            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12091            this.change_selections(Default::default(), window, cx, |s| {
12092                s.select(selections);
12093            });
12094        });
12095    }
12096
12097    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12099        if self.mode.is_single_line() {
12100            cx.propagate();
12101            return;
12102        }
12103
12104        self.rewrap_impl(RewrapOptions::default(), cx)
12105    }
12106
12107    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12108        let buffer = self.buffer.read(cx).snapshot(cx);
12109        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12110
12111        #[derive(Clone, Debug, PartialEq)]
12112        enum CommentFormat {
12113            /// single line comment, with prefix for line
12114            Line(String),
12115            /// single line within a block comment, with prefix for line
12116            BlockLine(String),
12117            /// a single line of a block comment that includes the initial delimiter
12118            BlockCommentWithStart(BlockCommentConfig),
12119            /// a single line of a block comment that includes the ending delimiter
12120            BlockCommentWithEnd(BlockCommentConfig),
12121        }
12122
12123        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12124        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12125            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12126                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12127                .peekable();
12128
12129            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12130                row
12131            } else {
12132                return Vec::new();
12133            };
12134
12135            let language_settings = buffer.language_settings_at(selection.head(), cx);
12136            let language_scope = buffer.language_scope_at(selection.head());
12137
12138            let indent_and_prefix_for_row =
12139                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12140                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12141                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12142                        &language_scope
12143                    {
12144                        let indent_end = Point::new(row, indent.len);
12145                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12146                        let line_text_after_indent = buffer
12147                            .text_for_range(indent_end..line_end)
12148                            .collect::<String>();
12149
12150                        let is_within_comment_override = buffer
12151                            .language_scope_at(indent_end)
12152                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12153                        let comment_delimiters = if is_within_comment_override {
12154                            // we are within a comment syntax node, but we don't
12155                            // yet know what kind of comment: block, doc or line
12156                            match (
12157                                language_scope.documentation_comment(),
12158                                language_scope.block_comment(),
12159                            ) {
12160                                (Some(config), _) | (_, Some(config))
12161                                    if buffer.contains_str_at(indent_end, &config.start) =>
12162                                {
12163                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12164                                }
12165                                (Some(config), _) | (_, Some(config))
12166                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12167                                {
12168                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12169                                }
12170                                (Some(config), _) | (_, Some(config))
12171                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12172                                {
12173                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12174                                }
12175                                (_, _) => language_scope
12176                                    .line_comment_prefixes()
12177                                    .iter()
12178                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12179                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12180                            }
12181                        } else {
12182                            // we not in an overridden comment node, but we may
12183                            // be within a non-overridden line comment node
12184                            language_scope
12185                                .line_comment_prefixes()
12186                                .iter()
12187                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12188                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12189                        };
12190
12191                        let rewrap_prefix = language_scope
12192                            .rewrap_prefixes()
12193                            .iter()
12194                            .find_map(|prefix_regex| {
12195                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12196                                    if mat.start() == 0 {
12197                                        Some(mat.as_str().to_string())
12198                                    } else {
12199                                        None
12200                                    }
12201                                })
12202                            })
12203                            .flatten();
12204                        (comment_delimiters, rewrap_prefix)
12205                    } else {
12206                        (None, None)
12207                    };
12208                    (indent, comment_prefix, rewrap_prefix)
12209                };
12210
12211            let mut ranges = Vec::new();
12212            let from_empty_selection = selection.is_empty();
12213
12214            let mut current_range_start = first_row;
12215            let mut prev_row = first_row;
12216            let (
12217                mut current_range_indent,
12218                mut current_range_comment_delimiters,
12219                mut current_range_rewrap_prefix,
12220            ) = indent_and_prefix_for_row(first_row);
12221
12222            for row in non_blank_rows_iter.skip(1) {
12223                let has_paragraph_break = row > prev_row + 1;
12224
12225                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12226                    indent_and_prefix_for_row(row);
12227
12228                let has_indent_change = row_indent != current_range_indent;
12229                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12230
12231                let has_boundary_change = has_comment_change
12232                    || row_rewrap_prefix.is_some()
12233                    || (has_indent_change && current_range_comment_delimiters.is_some());
12234
12235                if has_paragraph_break || has_boundary_change {
12236                    ranges.push((
12237                        language_settings.clone(),
12238                        Point::new(current_range_start, 0)
12239                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12240                        current_range_indent,
12241                        current_range_comment_delimiters.clone(),
12242                        current_range_rewrap_prefix.clone(),
12243                        from_empty_selection,
12244                    ));
12245                    current_range_start = row;
12246                    current_range_indent = row_indent;
12247                    current_range_comment_delimiters = row_comment_delimiters;
12248                    current_range_rewrap_prefix = row_rewrap_prefix;
12249                }
12250                prev_row = row;
12251            }
12252
12253            ranges.push((
12254                language_settings.clone(),
12255                Point::new(current_range_start, 0)
12256                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12257                current_range_indent,
12258                current_range_comment_delimiters,
12259                current_range_rewrap_prefix,
12260                from_empty_selection,
12261            ));
12262
12263            ranges
12264        });
12265
12266        let mut edits = Vec::new();
12267        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12268
12269        for (
12270            language_settings,
12271            wrap_range,
12272            mut indent_size,
12273            comment_prefix,
12274            rewrap_prefix,
12275            from_empty_selection,
12276        ) in wrap_ranges
12277        {
12278            let mut start_row = wrap_range.start.row;
12279            let mut end_row = wrap_range.end.row;
12280
12281            // Skip selections that overlap with a range that has already been rewrapped.
12282            let selection_range = start_row..end_row;
12283            if rewrapped_row_ranges
12284                .iter()
12285                .any(|range| range.overlaps(&selection_range))
12286            {
12287                continue;
12288            }
12289
12290            let tab_size = language_settings.tab_size;
12291
12292            let (line_prefix, inside_comment) = match &comment_prefix {
12293                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12294                    (Some(prefix.as_str()), true)
12295                }
12296                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12297                    (Some(prefix.as_ref()), true)
12298                }
12299                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12300                    start: _,
12301                    end: _,
12302                    prefix,
12303                    tab_size,
12304                })) => {
12305                    indent_size.len += tab_size;
12306                    (Some(prefix.as_ref()), true)
12307                }
12308                None => (None, false),
12309            };
12310            let indent_prefix = indent_size.chars().collect::<String>();
12311            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12312
12313            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12314                RewrapBehavior::InComments => inside_comment,
12315                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12316                RewrapBehavior::Anywhere => true,
12317            };
12318
12319            let should_rewrap = options.override_language_settings
12320                || allow_rewrap_based_on_language
12321                || self.hard_wrap.is_some();
12322            if !should_rewrap {
12323                continue;
12324            }
12325
12326            if from_empty_selection {
12327                'expand_upwards: while start_row > 0 {
12328                    let prev_row = start_row - 1;
12329                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12330                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12331                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12332                    {
12333                        start_row = prev_row;
12334                    } else {
12335                        break 'expand_upwards;
12336                    }
12337                }
12338
12339                'expand_downwards: while end_row < buffer.max_point().row {
12340                    let next_row = end_row + 1;
12341                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12342                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12343                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12344                    {
12345                        end_row = next_row;
12346                    } else {
12347                        break 'expand_downwards;
12348                    }
12349                }
12350            }
12351
12352            let start = Point::new(start_row, 0);
12353            let start_offset = ToOffset::to_offset(&start, &buffer);
12354            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12355            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12356            let mut first_line_delimiter = None;
12357            let mut last_line_delimiter = None;
12358            let Some(lines_without_prefixes) = selection_text
12359                .lines()
12360                .enumerate()
12361                .map(|(ix, line)| {
12362                    let line_trimmed = line.trim_start();
12363                    if rewrap_prefix.is_some() && ix > 0 {
12364                        Ok(line_trimmed)
12365                    } else if let Some(
12366                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12367                            start,
12368                            prefix,
12369                            end,
12370                            tab_size,
12371                        })
12372                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12373                            start,
12374                            prefix,
12375                            end,
12376                            tab_size,
12377                        }),
12378                    ) = &comment_prefix
12379                    {
12380                        let line_trimmed = line_trimmed
12381                            .strip_prefix(start.as_ref())
12382                            .map(|s| {
12383                                let mut indent_size = indent_size;
12384                                indent_size.len -= tab_size;
12385                                let indent_prefix: String = indent_size.chars().collect();
12386                                first_line_delimiter = Some((indent_prefix, start));
12387                                s.trim_start()
12388                            })
12389                            .unwrap_or(line_trimmed);
12390                        let line_trimmed = line_trimmed
12391                            .strip_suffix(end.as_ref())
12392                            .map(|s| {
12393                                last_line_delimiter = Some(end);
12394                                s.trim_end()
12395                            })
12396                            .unwrap_or(line_trimmed);
12397                        let line_trimmed = line_trimmed
12398                            .strip_prefix(prefix.as_ref())
12399                            .unwrap_or(line_trimmed);
12400                        Ok(line_trimmed)
12401                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12402                        line_trimmed.strip_prefix(prefix).with_context(|| {
12403                            format!("line did not start with prefix {prefix:?}: {line:?}")
12404                        })
12405                    } else {
12406                        line_trimmed
12407                            .strip_prefix(&line_prefix.trim_start())
12408                            .with_context(|| {
12409                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12410                            })
12411                    }
12412                })
12413                .collect::<Result<Vec<_>, _>>()
12414                .log_err()
12415            else {
12416                continue;
12417            };
12418
12419            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12420                buffer
12421                    .language_settings_at(Point::new(start_row, 0), cx)
12422                    .preferred_line_length as usize
12423            });
12424
12425            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12426                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12427            } else {
12428                line_prefix.clone()
12429            };
12430
12431            let wrapped_text = {
12432                let mut wrapped_text = wrap_with_prefix(
12433                    line_prefix,
12434                    subsequent_lines_prefix,
12435                    lines_without_prefixes.join("\n"),
12436                    wrap_column,
12437                    tab_size,
12438                    options.preserve_existing_whitespace,
12439                );
12440
12441                if let Some((indent, delimiter)) = first_line_delimiter {
12442                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12443                }
12444                if let Some(last_line) = last_line_delimiter {
12445                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12446                }
12447
12448                wrapped_text
12449            };
12450
12451            // TODO: should always use char-based diff while still supporting cursor behavior that
12452            // matches vim.
12453            let mut diff_options = DiffOptions::default();
12454            if options.override_language_settings {
12455                diff_options.max_word_diff_len = 0;
12456                diff_options.max_word_diff_line_count = 0;
12457            } else {
12458                diff_options.max_word_diff_len = usize::MAX;
12459                diff_options.max_word_diff_line_count = usize::MAX;
12460            }
12461
12462            for (old_range, new_text) in
12463                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12464            {
12465                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12466                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12467                edits.push((edit_start..edit_end, new_text));
12468            }
12469
12470            rewrapped_row_ranges.push(start_row..=end_row);
12471        }
12472
12473        self.buffer
12474            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12475    }
12476
12477    pub fn cut_common(
12478        &mut self,
12479        cut_no_selection_line: bool,
12480        window: &mut Window,
12481        cx: &mut Context<Self>,
12482    ) -> ClipboardItem {
12483        let mut text = String::new();
12484        let buffer = self.buffer.read(cx).snapshot(cx);
12485        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12486        let mut clipboard_selections = Vec::with_capacity(selections.len());
12487        {
12488            let max_point = buffer.max_point();
12489            let mut is_first = true;
12490            for selection in &mut selections {
12491                let is_entire_line =
12492                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12493                if is_entire_line {
12494                    selection.start = Point::new(selection.start.row, 0);
12495                    if !selection.is_empty() && selection.end.column == 0 {
12496                        selection.end = cmp::min(max_point, selection.end);
12497                    } else {
12498                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12499                    }
12500                    selection.goal = SelectionGoal::None;
12501                }
12502                if is_first {
12503                    is_first = false;
12504                } else {
12505                    text += "\n";
12506                }
12507                let mut len = 0;
12508                for chunk in buffer.text_for_range(selection.start..selection.end) {
12509                    text.push_str(chunk);
12510                    len += chunk.len();
12511                }
12512                clipboard_selections.push(ClipboardSelection {
12513                    len,
12514                    is_entire_line,
12515                    first_line_indent: buffer
12516                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12517                        .len,
12518                });
12519            }
12520        }
12521
12522        self.transact(window, cx, |this, window, cx| {
12523            this.change_selections(Default::default(), window, cx, |s| {
12524                s.select(selections);
12525            });
12526            this.insert("", window, cx);
12527        });
12528        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12529    }
12530
12531    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12533        let item = self.cut_common(true, window, cx);
12534        cx.write_to_clipboard(item);
12535    }
12536
12537    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12538        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12539        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12540            s.move_with(|snapshot, sel| {
12541                if sel.is_empty() {
12542                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12543                }
12544                if sel.is_empty() {
12545                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12546                }
12547            });
12548        });
12549        let item = self.cut_common(false, window, cx);
12550        cx.set_global(KillRing(item))
12551    }
12552
12553    pub fn kill_ring_yank(
12554        &mut self,
12555        _: &KillRingYank,
12556        window: &mut Window,
12557        cx: &mut Context<Self>,
12558    ) {
12559        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12560        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12561            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12562                (kill_ring.text().to_string(), kill_ring.metadata_json())
12563            } else {
12564                return;
12565            }
12566        } else {
12567            return;
12568        };
12569        self.do_paste(&text, metadata, false, window, cx);
12570    }
12571
12572    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12573        self.do_copy(true, cx);
12574    }
12575
12576    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12577        self.do_copy(false, cx);
12578    }
12579
12580    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12581        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12582        let buffer = self.buffer.read(cx).read(cx);
12583        let mut text = String::new();
12584
12585        let mut clipboard_selections = Vec::with_capacity(selections.len());
12586        {
12587            let max_point = buffer.max_point();
12588            let mut is_first = true;
12589            for selection in &selections {
12590                let mut start = selection.start;
12591                let mut end = selection.end;
12592                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12593                let mut add_trailing_newline = false;
12594                if is_entire_line {
12595                    start = Point::new(start.row, 0);
12596                    let next_line_start = Point::new(end.row + 1, 0);
12597                    if next_line_start <= max_point {
12598                        end = next_line_start;
12599                    } else {
12600                        // We're on the last line without a trailing newline.
12601                        // Copy to the end of the line and add a newline afterwards.
12602                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12603                        add_trailing_newline = true;
12604                    }
12605                }
12606
12607                let mut trimmed_selections = Vec::new();
12608                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12609                    let row = MultiBufferRow(start.row);
12610                    let first_indent = buffer.indent_size_for_line(row);
12611                    if first_indent.len == 0 || start.column > first_indent.len {
12612                        trimmed_selections.push(start..end);
12613                    } else {
12614                        trimmed_selections.push(
12615                            Point::new(row.0, first_indent.len)
12616                                ..Point::new(row.0, buffer.line_len(row)),
12617                        );
12618                        for row in start.row + 1..=end.row {
12619                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12620                            if row == end.row {
12621                                line_len = end.column;
12622                            }
12623                            if line_len == 0 {
12624                                trimmed_selections
12625                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12626                                continue;
12627                            }
12628                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12629                            if row_indent_size.len >= first_indent.len {
12630                                trimmed_selections.push(
12631                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12632                                );
12633                            } else {
12634                                trimmed_selections.clear();
12635                                trimmed_selections.push(start..end);
12636                                break;
12637                            }
12638                        }
12639                    }
12640                } else {
12641                    trimmed_selections.push(start..end);
12642                }
12643
12644                for trimmed_range in trimmed_selections {
12645                    if is_first {
12646                        is_first = false;
12647                    } else {
12648                        text += "\n";
12649                    }
12650                    let mut len = 0;
12651                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12652                        text.push_str(chunk);
12653                        len += chunk.len();
12654                    }
12655                    if add_trailing_newline {
12656                        text.push('\n');
12657                        len += 1;
12658                    }
12659                    clipboard_selections.push(ClipboardSelection {
12660                        len,
12661                        is_entire_line,
12662                        first_line_indent: buffer
12663                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12664                            .len,
12665                    });
12666                }
12667            }
12668        }
12669
12670        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12671            text,
12672            clipboard_selections,
12673        ));
12674    }
12675
12676    pub fn do_paste(
12677        &mut self,
12678        text: &String,
12679        clipboard_selections: Option<Vec<ClipboardSelection>>,
12680        handle_entire_lines: bool,
12681        window: &mut Window,
12682        cx: &mut Context<Self>,
12683    ) {
12684        if self.read_only(cx) {
12685            return;
12686        }
12687
12688        let clipboard_text = Cow::Borrowed(text.as_str());
12689
12690        self.transact(window, cx, |this, window, cx| {
12691            let had_active_edit_prediction = this.has_active_edit_prediction();
12692            let display_map = this.display_snapshot(cx);
12693            let old_selections = this.selections.all::<usize>(&display_map);
12694            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12695
12696            if let Some(mut clipboard_selections) = clipboard_selections {
12697                let all_selections_were_entire_line =
12698                    clipboard_selections.iter().all(|s| s.is_entire_line);
12699                let first_selection_indent_column =
12700                    clipboard_selections.first().map(|s| s.first_line_indent);
12701                if clipboard_selections.len() != old_selections.len() {
12702                    clipboard_selections.drain(..);
12703                }
12704                let mut auto_indent_on_paste = true;
12705
12706                this.buffer.update(cx, |buffer, cx| {
12707                    let snapshot = buffer.read(cx);
12708                    auto_indent_on_paste = snapshot
12709                        .language_settings_at(cursor_offset, cx)
12710                        .auto_indent_on_paste;
12711
12712                    let mut start_offset = 0;
12713                    let mut edits = Vec::new();
12714                    let mut original_indent_columns = Vec::new();
12715                    for (ix, selection) in old_selections.iter().enumerate() {
12716                        let to_insert;
12717                        let entire_line;
12718                        let original_indent_column;
12719                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12720                            let end_offset = start_offset + clipboard_selection.len;
12721                            to_insert = &clipboard_text[start_offset..end_offset];
12722                            entire_line = clipboard_selection.is_entire_line;
12723                            start_offset = end_offset + 1;
12724                            original_indent_column = Some(clipboard_selection.first_line_indent);
12725                        } else {
12726                            to_insert = &*clipboard_text;
12727                            entire_line = all_selections_were_entire_line;
12728                            original_indent_column = first_selection_indent_column
12729                        }
12730
12731                        let (range, to_insert) =
12732                            if selection.is_empty() && handle_entire_lines && entire_line {
12733                                // If the corresponding selection was empty when this slice of the
12734                                // clipboard text was written, then the entire line containing the
12735                                // selection was copied. If this selection is also currently empty,
12736                                // then paste the line before the current line of the buffer.
12737                                let column = selection.start.to_point(&snapshot).column as usize;
12738                                let line_start = selection.start - column;
12739                                (line_start..line_start, Cow::Borrowed(to_insert))
12740                            } else {
12741                                let language = snapshot.language_at(selection.head());
12742                                let range = selection.range();
12743                                if let Some(language) = language
12744                                    && language.name() == "Markdown".into()
12745                                {
12746                                    edit_for_markdown_paste(
12747                                        &snapshot,
12748                                        range,
12749                                        to_insert,
12750                                        url::Url::parse(to_insert).ok(),
12751                                    )
12752                                } else {
12753                                    (range, Cow::Borrowed(to_insert))
12754                                }
12755                            };
12756
12757                        edits.push((range, to_insert));
12758                        original_indent_columns.push(original_indent_column);
12759                    }
12760                    drop(snapshot);
12761
12762                    buffer.edit(
12763                        edits,
12764                        if auto_indent_on_paste {
12765                            Some(AutoindentMode::Block {
12766                                original_indent_columns,
12767                            })
12768                        } else {
12769                            None
12770                        },
12771                        cx,
12772                    );
12773                });
12774
12775                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12776                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12777            } else {
12778                let url = url::Url::parse(&clipboard_text).ok();
12779
12780                let auto_indent_mode = if !clipboard_text.is_empty() {
12781                    Some(AutoindentMode::Block {
12782                        original_indent_columns: Vec::new(),
12783                    })
12784                } else {
12785                    None
12786                };
12787
12788                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12789                    let snapshot = buffer.snapshot(cx);
12790
12791                    let anchors = old_selections
12792                        .iter()
12793                        .map(|s| {
12794                            let anchor = snapshot.anchor_after(s.head());
12795                            s.map(|_| anchor)
12796                        })
12797                        .collect::<Vec<_>>();
12798
12799                    let mut edits = Vec::new();
12800
12801                    for selection in old_selections.iter() {
12802                        let language = snapshot.language_at(selection.head());
12803                        let range = selection.range();
12804
12805                        let (edit_range, edit_text) = if let Some(language) = language
12806                            && language.name() == "Markdown".into()
12807                        {
12808                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12809                        } else {
12810                            (range, clipboard_text.clone())
12811                        };
12812
12813                        edits.push((edit_range, edit_text));
12814                    }
12815
12816                    drop(snapshot);
12817                    buffer.edit(edits, auto_indent_mode, cx);
12818
12819                    anchors
12820                });
12821
12822                this.change_selections(Default::default(), window, cx, |s| {
12823                    s.select_anchors(selection_anchors);
12824                });
12825            }
12826
12827            let trigger_in_words =
12828                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12829
12830            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12831        });
12832    }
12833
12834    pub fn diff_clipboard_with_selection(
12835        &mut self,
12836        _: &DiffClipboardWithSelection,
12837        window: &mut Window,
12838        cx: &mut Context<Self>,
12839    ) {
12840        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12841
12842        if selections.is_empty() {
12843            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12844            return;
12845        };
12846
12847        let clipboard_text = match cx.read_from_clipboard() {
12848            Some(item) => match item.entries().first() {
12849                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12850                _ => None,
12851            },
12852            None => None,
12853        };
12854
12855        let Some(clipboard_text) = clipboard_text else {
12856            log::warn!("Clipboard doesn't contain text.");
12857            return;
12858        };
12859
12860        window.dispatch_action(
12861            Box::new(DiffClipboardWithSelectionData {
12862                clipboard_text,
12863                editor: cx.entity(),
12864            }),
12865            cx,
12866        );
12867    }
12868
12869    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12871        if let Some(item) = cx.read_from_clipboard() {
12872            let entries = item.entries();
12873
12874            match entries.first() {
12875                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12876                // of all the pasted entries.
12877                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12878                    .do_paste(
12879                        clipboard_string.text(),
12880                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12881                        true,
12882                        window,
12883                        cx,
12884                    ),
12885                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12886            }
12887        }
12888    }
12889
12890    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12891        if self.read_only(cx) {
12892            return;
12893        }
12894
12895        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12896
12897        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12898            if let Some((selections, _)) =
12899                self.selection_history.transaction(transaction_id).cloned()
12900            {
12901                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12902                    s.select_anchors(selections.to_vec());
12903                });
12904            } else {
12905                log::error!(
12906                    "No entry in selection_history found for undo. \
12907                     This may correspond to a bug where undo does not update the selection. \
12908                     If this is occurring, please add details to \
12909                     https://github.com/zed-industries/zed/issues/22692"
12910                );
12911            }
12912            self.request_autoscroll(Autoscroll::fit(), cx);
12913            self.unmark_text(window, cx);
12914            self.refresh_edit_prediction(true, false, window, cx);
12915            cx.emit(EditorEvent::Edited { transaction_id });
12916            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12917        }
12918    }
12919
12920    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12921        if self.read_only(cx) {
12922            return;
12923        }
12924
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12926
12927        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12928            if let Some((_, Some(selections))) =
12929                self.selection_history.transaction(transaction_id).cloned()
12930            {
12931                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12932                    s.select_anchors(selections.to_vec());
12933                });
12934            } else {
12935                log::error!(
12936                    "No entry in selection_history found for redo. \
12937                     This may correspond to a bug where undo does not update the selection. \
12938                     If this is occurring, please add details to \
12939                     https://github.com/zed-industries/zed/issues/22692"
12940                );
12941            }
12942            self.request_autoscroll(Autoscroll::fit(), cx);
12943            self.unmark_text(window, cx);
12944            self.refresh_edit_prediction(true, false, window, cx);
12945            cx.emit(EditorEvent::Edited { transaction_id });
12946        }
12947    }
12948
12949    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12950        self.buffer
12951            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12952    }
12953
12954    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12955        self.buffer
12956            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12957    }
12958
12959    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12961        self.change_selections(Default::default(), window, cx, |s| {
12962            s.move_with(|map, selection| {
12963                let cursor = if selection.is_empty() {
12964                    movement::left(map, selection.start)
12965                } else {
12966                    selection.start
12967                };
12968                selection.collapse_to(cursor, SelectionGoal::None);
12969            });
12970        })
12971    }
12972
12973    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12975        self.change_selections(Default::default(), window, cx, |s| {
12976            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12977        })
12978    }
12979
12980    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12982        self.change_selections(Default::default(), window, cx, |s| {
12983            s.move_with(|map, selection| {
12984                let cursor = if selection.is_empty() {
12985                    movement::right(map, selection.end)
12986                } else {
12987                    selection.end
12988                };
12989                selection.collapse_to(cursor, SelectionGoal::None)
12990            });
12991        })
12992    }
12993
12994    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12996        self.change_selections(Default::default(), window, cx, |s| {
12997            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12998        });
12999    }
13000
13001    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13002        if self.take_rename(true, window, cx).is_some() {
13003            return;
13004        }
13005
13006        if self.mode.is_single_line() {
13007            cx.propagate();
13008            return;
13009        }
13010
13011        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13012
13013        let text_layout_details = &self.text_layout_details(window);
13014        let selection_count = self.selections.count();
13015        let first_selection = self.selections.first_anchor();
13016
13017        self.change_selections(Default::default(), window, cx, |s| {
13018            s.move_with(|map, selection| {
13019                if !selection.is_empty() {
13020                    selection.goal = SelectionGoal::None;
13021                }
13022                let (cursor, goal) = movement::up(
13023                    map,
13024                    selection.start,
13025                    selection.goal,
13026                    false,
13027                    text_layout_details,
13028                );
13029                selection.collapse_to(cursor, goal);
13030            });
13031        });
13032
13033        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13034        {
13035            cx.propagate();
13036        }
13037    }
13038
13039    pub fn move_up_by_lines(
13040        &mut self,
13041        action: &MoveUpByLines,
13042        window: &mut Window,
13043        cx: &mut Context<Self>,
13044    ) {
13045        if self.take_rename(true, window, cx).is_some() {
13046            return;
13047        }
13048
13049        if self.mode.is_single_line() {
13050            cx.propagate();
13051            return;
13052        }
13053
13054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13055
13056        let text_layout_details = &self.text_layout_details(window);
13057
13058        self.change_selections(Default::default(), window, cx, |s| {
13059            s.move_with(|map, selection| {
13060                if !selection.is_empty() {
13061                    selection.goal = SelectionGoal::None;
13062                }
13063                let (cursor, goal) = movement::up_by_rows(
13064                    map,
13065                    selection.start,
13066                    action.lines,
13067                    selection.goal,
13068                    false,
13069                    text_layout_details,
13070                );
13071                selection.collapse_to(cursor, goal);
13072            });
13073        })
13074    }
13075
13076    pub fn move_down_by_lines(
13077        &mut self,
13078        action: &MoveDownByLines,
13079        window: &mut Window,
13080        cx: &mut Context<Self>,
13081    ) {
13082        if self.take_rename(true, window, cx).is_some() {
13083            return;
13084        }
13085
13086        if self.mode.is_single_line() {
13087            cx.propagate();
13088            return;
13089        }
13090
13091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13092
13093        let text_layout_details = &self.text_layout_details(window);
13094
13095        self.change_selections(Default::default(), window, cx, |s| {
13096            s.move_with(|map, selection| {
13097                if !selection.is_empty() {
13098                    selection.goal = SelectionGoal::None;
13099                }
13100                let (cursor, goal) = movement::down_by_rows(
13101                    map,
13102                    selection.start,
13103                    action.lines,
13104                    selection.goal,
13105                    false,
13106                    text_layout_details,
13107                );
13108                selection.collapse_to(cursor, goal);
13109            });
13110        })
13111    }
13112
13113    pub fn select_down_by_lines(
13114        &mut self,
13115        action: &SelectDownByLines,
13116        window: &mut Window,
13117        cx: &mut Context<Self>,
13118    ) {
13119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13120        let text_layout_details = &self.text_layout_details(window);
13121        self.change_selections(Default::default(), window, cx, |s| {
13122            s.move_heads_with(|map, head, goal| {
13123                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13124            })
13125        })
13126    }
13127
13128    pub fn select_up_by_lines(
13129        &mut self,
13130        action: &SelectUpByLines,
13131        window: &mut Window,
13132        cx: &mut Context<Self>,
13133    ) {
13134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13135        let text_layout_details = &self.text_layout_details(window);
13136        self.change_selections(Default::default(), window, cx, |s| {
13137            s.move_heads_with(|map, head, goal| {
13138                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13139            })
13140        })
13141    }
13142
13143    pub fn select_page_up(
13144        &mut self,
13145        _: &SelectPageUp,
13146        window: &mut Window,
13147        cx: &mut Context<Self>,
13148    ) {
13149        let Some(row_count) = self.visible_row_count() else {
13150            return;
13151        };
13152
13153        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13154
13155        let text_layout_details = &self.text_layout_details(window);
13156
13157        self.change_selections(Default::default(), window, cx, |s| {
13158            s.move_heads_with(|map, head, goal| {
13159                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13160            })
13161        })
13162    }
13163
13164    pub fn move_page_up(
13165        &mut self,
13166        action: &MovePageUp,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if self.take_rename(true, window, cx).is_some() {
13171            return;
13172        }
13173
13174        if self
13175            .context_menu
13176            .borrow_mut()
13177            .as_mut()
13178            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13179            .unwrap_or(false)
13180        {
13181            return;
13182        }
13183
13184        if matches!(self.mode, EditorMode::SingleLine) {
13185            cx.propagate();
13186            return;
13187        }
13188
13189        let Some(row_count) = self.visible_row_count() else {
13190            return;
13191        };
13192
13193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13194
13195        let effects = if action.center_cursor {
13196            SelectionEffects::scroll(Autoscroll::center())
13197        } else {
13198            SelectionEffects::default()
13199        };
13200
13201        let text_layout_details = &self.text_layout_details(window);
13202
13203        self.change_selections(effects, window, cx, |s| {
13204            s.move_with(|map, selection| {
13205                if !selection.is_empty() {
13206                    selection.goal = SelectionGoal::None;
13207                }
13208                let (cursor, goal) = movement::up_by_rows(
13209                    map,
13210                    selection.end,
13211                    row_count,
13212                    selection.goal,
13213                    false,
13214                    text_layout_details,
13215                );
13216                selection.collapse_to(cursor, goal);
13217            });
13218        });
13219    }
13220
13221    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13222        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13223        let text_layout_details = &self.text_layout_details(window);
13224        self.change_selections(Default::default(), window, cx, |s| {
13225            s.move_heads_with(|map, head, goal| {
13226                movement::up(map, head, goal, false, text_layout_details)
13227            })
13228        })
13229    }
13230
13231    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13232        self.take_rename(true, window, cx);
13233
13234        if self.mode.is_single_line() {
13235            cx.propagate();
13236            return;
13237        }
13238
13239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13240
13241        let text_layout_details = &self.text_layout_details(window);
13242        let selection_count = self.selections.count();
13243        let first_selection = self.selections.first_anchor();
13244
13245        self.change_selections(Default::default(), window, cx, |s| {
13246            s.move_with(|map, selection| {
13247                if !selection.is_empty() {
13248                    selection.goal = SelectionGoal::None;
13249                }
13250                let (cursor, goal) = movement::down(
13251                    map,
13252                    selection.end,
13253                    selection.goal,
13254                    false,
13255                    text_layout_details,
13256                );
13257                selection.collapse_to(cursor, goal);
13258            });
13259        });
13260
13261        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13262        {
13263            cx.propagate();
13264        }
13265    }
13266
13267    pub fn select_page_down(
13268        &mut self,
13269        _: &SelectPageDown,
13270        window: &mut Window,
13271        cx: &mut Context<Self>,
13272    ) {
13273        let Some(row_count) = self.visible_row_count() else {
13274            return;
13275        };
13276
13277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13278
13279        let text_layout_details = &self.text_layout_details(window);
13280
13281        self.change_selections(Default::default(), window, cx, |s| {
13282            s.move_heads_with(|map, head, goal| {
13283                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13284            })
13285        })
13286    }
13287
13288    pub fn move_page_down(
13289        &mut self,
13290        action: &MovePageDown,
13291        window: &mut Window,
13292        cx: &mut Context<Self>,
13293    ) {
13294        if self.take_rename(true, window, cx).is_some() {
13295            return;
13296        }
13297
13298        if self
13299            .context_menu
13300            .borrow_mut()
13301            .as_mut()
13302            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13303            .unwrap_or(false)
13304        {
13305            return;
13306        }
13307
13308        if matches!(self.mode, EditorMode::SingleLine) {
13309            cx.propagate();
13310            return;
13311        }
13312
13313        let Some(row_count) = self.visible_row_count() else {
13314            return;
13315        };
13316
13317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13318
13319        let effects = if action.center_cursor {
13320            SelectionEffects::scroll(Autoscroll::center())
13321        } else {
13322            SelectionEffects::default()
13323        };
13324
13325        let text_layout_details = &self.text_layout_details(window);
13326        self.change_selections(effects, window, cx, |s| {
13327            s.move_with(|map, selection| {
13328                if !selection.is_empty() {
13329                    selection.goal = SelectionGoal::None;
13330                }
13331                let (cursor, goal) = movement::down_by_rows(
13332                    map,
13333                    selection.end,
13334                    row_count,
13335                    selection.goal,
13336                    false,
13337                    text_layout_details,
13338                );
13339                selection.collapse_to(cursor, goal);
13340            });
13341        });
13342    }
13343
13344    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13346        let text_layout_details = &self.text_layout_details(window);
13347        self.change_selections(Default::default(), window, cx, |s| {
13348            s.move_heads_with(|map, head, goal| {
13349                movement::down(map, head, goal, false, text_layout_details)
13350            })
13351        });
13352    }
13353
13354    pub fn context_menu_first(
13355        &mut self,
13356        _: &ContextMenuFirst,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) {
13360        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13361            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13362        }
13363    }
13364
13365    pub fn context_menu_prev(
13366        &mut self,
13367        _: &ContextMenuPrevious,
13368        window: &mut Window,
13369        cx: &mut Context<Self>,
13370    ) {
13371        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13372            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13373        }
13374    }
13375
13376    pub fn context_menu_next(
13377        &mut self,
13378        _: &ContextMenuNext,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13383            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13384        }
13385    }
13386
13387    pub fn context_menu_last(
13388        &mut self,
13389        _: &ContextMenuLast,
13390        window: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) {
13393        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13394            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13395        }
13396    }
13397
13398    pub fn signature_help_prev(
13399        &mut self,
13400        _: &SignatureHelpPrevious,
13401        _: &mut Window,
13402        cx: &mut Context<Self>,
13403    ) {
13404        if let Some(popover) = self.signature_help_state.popover_mut() {
13405            if popover.current_signature == 0 {
13406                popover.current_signature = popover.signatures.len() - 1;
13407            } else {
13408                popover.current_signature -= 1;
13409            }
13410            cx.notify();
13411        }
13412    }
13413
13414    pub fn signature_help_next(
13415        &mut self,
13416        _: &SignatureHelpNext,
13417        _: &mut Window,
13418        cx: &mut Context<Self>,
13419    ) {
13420        if let Some(popover) = self.signature_help_state.popover_mut() {
13421            if popover.current_signature + 1 == popover.signatures.len() {
13422                popover.current_signature = 0;
13423            } else {
13424                popover.current_signature += 1;
13425            }
13426            cx.notify();
13427        }
13428    }
13429
13430    pub fn move_to_previous_word_start(
13431        &mut self,
13432        _: &MoveToPreviousWordStart,
13433        window: &mut Window,
13434        cx: &mut Context<Self>,
13435    ) {
13436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13437        self.change_selections(Default::default(), window, cx, |s| {
13438            s.move_cursors_with(|map, head, _| {
13439                (
13440                    movement::previous_word_start(map, head),
13441                    SelectionGoal::None,
13442                )
13443            });
13444        })
13445    }
13446
13447    pub fn move_to_previous_subword_start(
13448        &mut self,
13449        _: &MoveToPreviousSubwordStart,
13450        window: &mut Window,
13451        cx: &mut Context<Self>,
13452    ) {
13453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13454        self.change_selections(Default::default(), window, cx, |s| {
13455            s.move_cursors_with(|map, head, _| {
13456                (
13457                    movement::previous_subword_start(map, head),
13458                    SelectionGoal::None,
13459                )
13460            });
13461        })
13462    }
13463
13464    pub fn select_to_previous_word_start(
13465        &mut self,
13466        _: &SelectToPreviousWordStart,
13467        window: &mut Window,
13468        cx: &mut Context<Self>,
13469    ) {
13470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13471        self.change_selections(Default::default(), window, cx, |s| {
13472            s.move_heads_with(|map, head, _| {
13473                (
13474                    movement::previous_word_start(map, head),
13475                    SelectionGoal::None,
13476                )
13477            });
13478        })
13479    }
13480
13481    pub fn select_to_previous_subword_start(
13482        &mut self,
13483        _: &SelectToPreviousSubwordStart,
13484        window: &mut Window,
13485        cx: &mut Context<Self>,
13486    ) {
13487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13488        self.change_selections(Default::default(), window, cx, |s| {
13489            s.move_heads_with(|map, head, _| {
13490                (
13491                    movement::previous_subword_start(map, head),
13492                    SelectionGoal::None,
13493                )
13494            });
13495        })
13496    }
13497
13498    pub fn delete_to_previous_word_start(
13499        &mut self,
13500        action: &DeleteToPreviousWordStart,
13501        window: &mut Window,
13502        cx: &mut Context<Self>,
13503    ) {
13504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13505        self.transact(window, cx, |this, window, cx| {
13506            this.select_autoclose_pair(window, cx);
13507            this.change_selections(Default::default(), window, cx, |s| {
13508                s.move_with(|map, selection| {
13509                    if selection.is_empty() {
13510                        let mut cursor = if action.ignore_newlines {
13511                            movement::previous_word_start(map, selection.head())
13512                        } else {
13513                            movement::previous_word_start_or_newline(map, selection.head())
13514                        };
13515                        cursor = movement::adjust_greedy_deletion(
13516                            map,
13517                            selection.head(),
13518                            cursor,
13519                            action.ignore_brackets,
13520                        );
13521                        selection.set_head(cursor, SelectionGoal::None);
13522                    }
13523                });
13524            });
13525            this.insert("", window, cx);
13526        });
13527    }
13528
13529    pub fn delete_to_previous_subword_start(
13530        &mut self,
13531        _: &DeleteToPreviousSubwordStart,
13532        window: &mut Window,
13533        cx: &mut Context<Self>,
13534    ) {
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13536        self.transact(window, cx, |this, window, cx| {
13537            this.select_autoclose_pair(window, cx);
13538            this.change_selections(Default::default(), window, cx, |s| {
13539                s.move_with(|map, selection| {
13540                    if selection.is_empty() {
13541                        let mut cursor = movement::previous_subword_start(map, selection.head());
13542                        cursor =
13543                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13544                        selection.set_head(cursor, SelectionGoal::None);
13545                    }
13546                });
13547            });
13548            this.insert("", window, cx);
13549        });
13550    }
13551
13552    pub fn move_to_next_word_end(
13553        &mut self,
13554        _: &MoveToNextWordEnd,
13555        window: &mut Window,
13556        cx: &mut Context<Self>,
13557    ) {
13558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13559        self.change_selections(Default::default(), window, cx, |s| {
13560            s.move_cursors_with(|map, head, _| {
13561                (movement::next_word_end(map, head), SelectionGoal::None)
13562            });
13563        })
13564    }
13565
13566    pub fn move_to_next_subword_end(
13567        &mut self,
13568        _: &MoveToNextSubwordEnd,
13569        window: &mut Window,
13570        cx: &mut Context<Self>,
13571    ) {
13572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13573        self.change_selections(Default::default(), window, cx, |s| {
13574            s.move_cursors_with(|map, head, _| {
13575                (movement::next_subword_end(map, head), SelectionGoal::None)
13576            });
13577        })
13578    }
13579
13580    pub fn select_to_next_word_end(
13581        &mut self,
13582        _: &SelectToNextWordEnd,
13583        window: &mut Window,
13584        cx: &mut Context<Self>,
13585    ) {
13586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13587        self.change_selections(Default::default(), window, cx, |s| {
13588            s.move_heads_with(|map, head, _| {
13589                (movement::next_word_end(map, head), SelectionGoal::None)
13590            });
13591        })
13592    }
13593
13594    pub fn select_to_next_subword_end(
13595        &mut self,
13596        _: &SelectToNextSubwordEnd,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) {
13600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13601        self.change_selections(Default::default(), window, cx, |s| {
13602            s.move_heads_with(|map, head, _| {
13603                (movement::next_subword_end(map, head), SelectionGoal::None)
13604            });
13605        })
13606    }
13607
13608    pub fn delete_to_next_word_end(
13609        &mut self,
13610        action: &DeleteToNextWordEnd,
13611        window: &mut Window,
13612        cx: &mut Context<Self>,
13613    ) {
13614        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13615        self.transact(window, cx, |this, window, cx| {
13616            this.change_selections(Default::default(), window, cx, |s| {
13617                s.move_with(|map, selection| {
13618                    if selection.is_empty() {
13619                        let mut cursor = if action.ignore_newlines {
13620                            movement::next_word_end(map, selection.head())
13621                        } else {
13622                            movement::next_word_end_or_newline(map, selection.head())
13623                        };
13624                        cursor = movement::adjust_greedy_deletion(
13625                            map,
13626                            selection.head(),
13627                            cursor,
13628                            action.ignore_brackets,
13629                        );
13630                        selection.set_head(cursor, SelectionGoal::None);
13631                    }
13632                });
13633            });
13634            this.insert("", window, cx);
13635        });
13636    }
13637
13638    pub fn delete_to_next_subword_end(
13639        &mut self,
13640        _: &DeleteToNextSubwordEnd,
13641        window: &mut Window,
13642        cx: &mut Context<Self>,
13643    ) {
13644        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13645        self.transact(window, cx, |this, window, cx| {
13646            this.change_selections(Default::default(), window, cx, |s| {
13647                s.move_with(|map, selection| {
13648                    if selection.is_empty() {
13649                        let mut cursor = movement::next_subword_end(map, selection.head());
13650                        cursor =
13651                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13652                        selection.set_head(cursor, SelectionGoal::None);
13653                    }
13654                });
13655            });
13656            this.insert("", window, cx);
13657        });
13658    }
13659
13660    pub fn move_to_beginning_of_line(
13661        &mut self,
13662        action: &MoveToBeginningOfLine,
13663        window: &mut Window,
13664        cx: &mut Context<Self>,
13665    ) {
13666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13667        self.change_selections(Default::default(), window, cx, |s| {
13668            s.move_cursors_with(|map, head, _| {
13669                (
13670                    movement::indented_line_beginning(
13671                        map,
13672                        head,
13673                        action.stop_at_soft_wraps,
13674                        action.stop_at_indent,
13675                    ),
13676                    SelectionGoal::None,
13677                )
13678            });
13679        })
13680    }
13681
13682    pub fn select_to_beginning_of_line(
13683        &mut self,
13684        action: &SelectToBeginningOfLine,
13685        window: &mut Window,
13686        cx: &mut Context<Self>,
13687    ) {
13688        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13689        self.change_selections(Default::default(), window, cx, |s| {
13690            s.move_heads_with(|map, head, _| {
13691                (
13692                    movement::indented_line_beginning(
13693                        map,
13694                        head,
13695                        action.stop_at_soft_wraps,
13696                        action.stop_at_indent,
13697                    ),
13698                    SelectionGoal::None,
13699                )
13700            });
13701        });
13702    }
13703
13704    pub fn delete_to_beginning_of_line(
13705        &mut self,
13706        action: &DeleteToBeginningOfLine,
13707        window: &mut Window,
13708        cx: &mut Context<Self>,
13709    ) {
13710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13711        self.transact(window, cx, |this, window, cx| {
13712            this.change_selections(Default::default(), window, cx, |s| {
13713                s.move_with(|_, selection| {
13714                    selection.reversed = true;
13715                });
13716            });
13717
13718            this.select_to_beginning_of_line(
13719                &SelectToBeginningOfLine {
13720                    stop_at_soft_wraps: false,
13721                    stop_at_indent: action.stop_at_indent,
13722                },
13723                window,
13724                cx,
13725            );
13726            this.backspace(&Backspace, window, cx);
13727        });
13728    }
13729
13730    pub fn move_to_end_of_line(
13731        &mut self,
13732        action: &MoveToEndOfLine,
13733        window: &mut Window,
13734        cx: &mut Context<Self>,
13735    ) {
13736        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13737        self.change_selections(Default::default(), window, cx, |s| {
13738            s.move_cursors_with(|map, head, _| {
13739                (
13740                    movement::line_end(map, head, action.stop_at_soft_wraps),
13741                    SelectionGoal::None,
13742                )
13743            });
13744        })
13745    }
13746
13747    pub fn select_to_end_of_line(
13748        &mut self,
13749        action: &SelectToEndOfLine,
13750        window: &mut Window,
13751        cx: &mut Context<Self>,
13752    ) {
13753        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13754        self.change_selections(Default::default(), window, cx, |s| {
13755            s.move_heads_with(|map, head, _| {
13756                (
13757                    movement::line_end(map, head, action.stop_at_soft_wraps),
13758                    SelectionGoal::None,
13759                )
13760            });
13761        })
13762    }
13763
13764    pub fn delete_to_end_of_line(
13765        &mut self,
13766        _: &DeleteToEndOfLine,
13767        window: &mut Window,
13768        cx: &mut Context<Self>,
13769    ) {
13770        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13771        self.transact(window, cx, |this, window, cx| {
13772            this.select_to_end_of_line(
13773                &SelectToEndOfLine {
13774                    stop_at_soft_wraps: false,
13775                },
13776                window,
13777                cx,
13778            );
13779            this.delete(&Delete, window, cx);
13780        });
13781    }
13782
13783    pub fn cut_to_end_of_line(
13784        &mut self,
13785        action: &CutToEndOfLine,
13786        window: &mut Window,
13787        cx: &mut Context<Self>,
13788    ) {
13789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13790        self.transact(window, cx, |this, window, cx| {
13791            this.select_to_end_of_line(
13792                &SelectToEndOfLine {
13793                    stop_at_soft_wraps: false,
13794                },
13795                window,
13796                cx,
13797            );
13798            if !action.stop_at_newlines {
13799                this.change_selections(Default::default(), window, cx, |s| {
13800                    s.move_with(|_, sel| {
13801                        if sel.is_empty() {
13802                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13803                        }
13804                    });
13805                });
13806            }
13807            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13808            let item = this.cut_common(false, window, cx);
13809            cx.write_to_clipboard(item);
13810        });
13811    }
13812
13813    pub fn move_to_start_of_paragraph(
13814        &mut self,
13815        _: &MoveToStartOfParagraph,
13816        window: &mut Window,
13817        cx: &mut Context<Self>,
13818    ) {
13819        if matches!(self.mode, EditorMode::SingleLine) {
13820            cx.propagate();
13821            return;
13822        }
13823        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13824        self.change_selections(Default::default(), window, cx, |s| {
13825            s.move_with(|map, selection| {
13826                selection.collapse_to(
13827                    movement::start_of_paragraph(map, selection.head(), 1),
13828                    SelectionGoal::None,
13829                )
13830            });
13831        })
13832    }
13833
13834    pub fn move_to_end_of_paragraph(
13835        &mut self,
13836        _: &MoveToEndOfParagraph,
13837        window: &mut Window,
13838        cx: &mut Context<Self>,
13839    ) {
13840        if matches!(self.mode, EditorMode::SingleLine) {
13841            cx.propagate();
13842            return;
13843        }
13844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13845        self.change_selections(Default::default(), window, cx, |s| {
13846            s.move_with(|map, selection| {
13847                selection.collapse_to(
13848                    movement::end_of_paragraph(map, selection.head(), 1),
13849                    SelectionGoal::None,
13850                )
13851            });
13852        })
13853    }
13854
13855    pub fn select_to_start_of_paragraph(
13856        &mut self,
13857        _: &SelectToStartOfParagraph,
13858        window: &mut Window,
13859        cx: &mut Context<Self>,
13860    ) {
13861        if matches!(self.mode, EditorMode::SingleLine) {
13862            cx.propagate();
13863            return;
13864        }
13865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13866        self.change_selections(Default::default(), window, cx, |s| {
13867            s.move_heads_with(|map, head, _| {
13868                (
13869                    movement::start_of_paragraph(map, head, 1),
13870                    SelectionGoal::None,
13871                )
13872            });
13873        })
13874    }
13875
13876    pub fn select_to_end_of_paragraph(
13877        &mut self,
13878        _: &SelectToEndOfParagraph,
13879        window: &mut Window,
13880        cx: &mut Context<Self>,
13881    ) {
13882        if matches!(self.mode, EditorMode::SingleLine) {
13883            cx.propagate();
13884            return;
13885        }
13886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13887        self.change_selections(Default::default(), window, cx, |s| {
13888            s.move_heads_with(|map, head, _| {
13889                (
13890                    movement::end_of_paragraph(map, head, 1),
13891                    SelectionGoal::None,
13892                )
13893            });
13894        })
13895    }
13896
13897    pub fn move_to_start_of_excerpt(
13898        &mut self,
13899        _: &MoveToStartOfExcerpt,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        if matches!(self.mode, EditorMode::SingleLine) {
13904            cx.propagate();
13905            return;
13906        }
13907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13908        self.change_selections(Default::default(), window, cx, |s| {
13909            s.move_with(|map, selection| {
13910                selection.collapse_to(
13911                    movement::start_of_excerpt(
13912                        map,
13913                        selection.head(),
13914                        workspace::searchable::Direction::Prev,
13915                    ),
13916                    SelectionGoal::None,
13917                )
13918            });
13919        })
13920    }
13921
13922    pub fn move_to_start_of_next_excerpt(
13923        &mut self,
13924        _: &MoveToStartOfNextExcerpt,
13925        window: &mut Window,
13926        cx: &mut Context<Self>,
13927    ) {
13928        if matches!(self.mode, EditorMode::SingleLine) {
13929            cx.propagate();
13930            return;
13931        }
13932
13933        self.change_selections(Default::default(), window, cx, |s| {
13934            s.move_with(|map, selection| {
13935                selection.collapse_to(
13936                    movement::start_of_excerpt(
13937                        map,
13938                        selection.head(),
13939                        workspace::searchable::Direction::Next,
13940                    ),
13941                    SelectionGoal::None,
13942                )
13943            });
13944        })
13945    }
13946
13947    pub fn move_to_end_of_excerpt(
13948        &mut self,
13949        _: &MoveToEndOfExcerpt,
13950        window: &mut Window,
13951        cx: &mut Context<Self>,
13952    ) {
13953        if matches!(self.mode, EditorMode::SingleLine) {
13954            cx.propagate();
13955            return;
13956        }
13957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13958        self.change_selections(Default::default(), window, cx, |s| {
13959            s.move_with(|map, selection| {
13960                selection.collapse_to(
13961                    movement::end_of_excerpt(
13962                        map,
13963                        selection.head(),
13964                        workspace::searchable::Direction::Next,
13965                    ),
13966                    SelectionGoal::None,
13967                )
13968            });
13969        })
13970    }
13971
13972    pub fn move_to_end_of_previous_excerpt(
13973        &mut self,
13974        _: &MoveToEndOfPreviousExcerpt,
13975        window: &mut Window,
13976        cx: &mut Context<Self>,
13977    ) {
13978        if matches!(self.mode, EditorMode::SingleLine) {
13979            cx.propagate();
13980            return;
13981        }
13982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13983        self.change_selections(Default::default(), window, cx, |s| {
13984            s.move_with(|map, selection| {
13985                selection.collapse_to(
13986                    movement::end_of_excerpt(
13987                        map,
13988                        selection.head(),
13989                        workspace::searchable::Direction::Prev,
13990                    ),
13991                    SelectionGoal::None,
13992                )
13993            });
13994        })
13995    }
13996
13997    pub fn select_to_start_of_excerpt(
13998        &mut self,
13999        _: &SelectToStartOfExcerpt,
14000        window: &mut Window,
14001        cx: &mut Context<Self>,
14002    ) {
14003        if matches!(self.mode, EditorMode::SingleLine) {
14004            cx.propagate();
14005            return;
14006        }
14007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14008        self.change_selections(Default::default(), window, cx, |s| {
14009            s.move_heads_with(|map, head, _| {
14010                (
14011                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14012                    SelectionGoal::None,
14013                )
14014            });
14015        })
14016    }
14017
14018    pub fn select_to_start_of_next_excerpt(
14019        &mut self,
14020        _: &SelectToStartOfNextExcerpt,
14021        window: &mut Window,
14022        cx: &mut Context<Self>,
14023    ) {
14024        if matches!(self.mode, EditorMode::SingleLine) {
14025            cx.propagate();
14026            return;
14027        }
14028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14029        self.change_selections(Default::default(), window, cx, |s| {
14030            s.move_heads_with(|map, head, _| {
14031                (
14032                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14033                    SelectionGoal::None,
14034                )
14035            });
14036        })
14037    }
14038
14039    pub fn select_to_end_of_excerpt(
14040        &mut self,
14041        _: &SelectToEndOfExcerpt,
14042        window: &mut Window,
14043        cx: &mut Context<Self>,
14044    ) {
14045        if matches!(self.mode, EditorMode::SingleLine) {
14046            cx.propagate();
14047            return;
14048        }
14049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14050        self.change_selections(Default::default(), window, cx, |s| {
14051            s.move_heads_with(|map, head, _| {
14052                (
14053                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14054                    SelectionGoal::None,
14055                )
14056            });
14057        })
14058    }
14059
14060    pub fn select_to_end_of_previous_excerpt(
14061        &mut self,
14062        _: &SelectToEndOfPreviousExcerpt,
14063        window: &mut Window,
14064        cx: &mut Context<Self>,
14065    ) {
14066        if matches!(self.mode, EditorMode::SingleLine) {
14067            cx.propagate();
14068            return;
14069        }
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071        self.change_selections(Default::default(), window, cx, |s| {
14072            s.move_heads_with(|map, head, _| {
14073                (
14074                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14075                    SelectionGoal::None,
14076                )
14077            });
14078        })
14079    }
14080
14081    pub fn move_to_beginning(
14082        &mut self,
14083        _: &MoveToBeginning,
14084        window: &mut Window,
14085        cx: &mut Context<Self>,
14086    ) {
14087        if matches!(self.mode, EditorMode::SingleLine) {
14088            cx.propagate();
14089            return;
14090        }
14091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14092        self.change_selections(Default::default(), window, cx, |s| {
14093            s.select_ranges(vec![0..0]);
14094        });
14095    }
14096
14097    pub fn select_to_beginning(
14098        &mut self,
14099        _: &SelectToBeginning,
14100        window: &mut Window,
14101        cx: &mut Context<Self>,
14102    ) {
14103        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14104        selection.set_head(Point::zero(), SelectionGoal::None);
14105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14106        self.change_selections(Default::default(), window, cx, |s| {
14107            s.select(vec![selection]);
14108        });
14109    }
14110
14111    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14112        if matches!(self.mode, EditorMode::SingleLine) {
14113            cx.propagate();
14114            return;
14115        }
14116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14117        let cursor = self.buffer.read(cx).read(cx).len();
14118        self.change_selections(Default::default(), window, cx, |s| {
14119            s.select_ranges(vec![cursor..cursor])
14120        });
14121    }
14122
14123    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14124        self.nav_history = nav_history;
14125    }
14126
14127    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14128        self.nav_history.as_ref()
14129    }
14130
14131    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14132        self.push_to_nav_history(
14133            self.selections.newest_anchor().head(),
14134            None,
14135            false,
14136            true,
14137            cx,
14138        );
14139    }
14140
14141    fn push_to_nav_history(
14142        &mut self,
14143        cursor_anchor: Anchor,
14144        new_position: Option<Point>,
14145        is_deactivate: bool,
14146        always: bool,
14147        cx: &mut Context<Self>,
14148    ) {
14149        if let Some(nav_history) = self.nav_history.as_mut() {
14150            let buffer = self.buffer.read(cx).read(cx);
14151            let cursor_position = cursor_anchor.to_point(&buffer);
14152            let scroll_state = self.scroll_manager.anchor();
14153            let scroll_top_row = scroll_state.top_row(&buffer);
14154            drop(buffer);
14155
14156            if let Some(new_position) = new_position {
14157                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14158                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14159                    return;
14160                }
14161            }
14162
14163            nav_history.push(
14164                Some(NavigationData {
14165                    cursor_anchor,
14166                    cursor_position,
14167                    scroll_anchor: scroll_state,
14168                    scroll_top_row,
14169                }),
14170                cx,
14171            );
14172            cx.emit(EditorEvent::PushedToNavHistory {
14173                anchor: cursor_anchor,
14174                is_deactivate,
14175            })
14176        }
14177    }
14178
14179    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14181        let buffer = self.buffer.read(cx).snapshot(cx);
14182        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14183        selection.set_head(buffer.len(), SelectionGoal::None);
14184        self.change_selections(Default::default(), window, cx, |s| {
14185            s.select(vec![selection]);
14186        });
14187    }
14188
14189    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14191        let end = self.buffer.read(cx).read(cx).len();
14192        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14193            s.select_ranges(vec![0..end]);
14194        });
14195    }
14196
14197    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14199        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14200        let mut selections = self.selections.all::<Point>(&display_map);
14201        let max_point = display_map.buffer_snapshot().max_point();
14202        for selection in &mut selections {
14203            let rows = selection.spanned_rows(true, &display_map);
14204            selection.start = Point::new(rows.start.0, 0);
14205            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14206            selection.reversed = false;
14207        }
14208        self.change_selections(Default::default(), window, cx, |s| {
14209            s.select(selections);
14210        });
14211    }
14212
14213    pub fn split_selection_into_lines(
14214        &mut self,
14215        action: &SplitSelectionIntoLines,
14216        window: &mut Window,
14217        cx: &mut Context<Self>,
14218    ) {
14219        let selections = self
14220            .selections
14221            .all::<Point>(&self.display_snapshot(cx))
14222            .into_iter()
14223            .map(|selection| selection.start..selection.end)
14224            .collect::<Vec<_>>();
14225        self.unfold_ranges(&selections, true, true, cx);
14226
14227        let mut new_selection_ranges = Vec::new();
14228        {
14229            let buffer = self.buffer.read(cx).read(cx);
14230            for selection in selections {
14231                for row in selection.start.row..selection.end.row {
14232                    let line_start = Point::new(row, 0);
14233                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14234
14235                    if action.keep_selections {
14236                        // Keep the selection range for each line
14237                        let selection_start = if row == selection.start.row {
14238                            selection.start
14239                        } else {
14240                            line_start
14241                        };
14242                        new_selection_ranges.push(selection_start..line_end);
14243                    } else {
14244                        // Collapse to cursor at end of line
14245                        new_selection_ranges.push(line_end..line_end);
14246                    }
14247                }
14248
14249                let is_multiline_selection = selection.start.row != selection.end.row;
14250                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14251                // so this action feels more ergonomic when paired with other selection operations
14252                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14253                if !should_skip_last {
14254                    if action.keep_selections {
14255                        if is_multiline_selection {
14256                            let line_start = Point::new(selection.end.row, 0);
14257                            new_selection_ranges.push(line_start..selection.end);
14258                        } else {
14259                            new_selection_ranges.push(selection.start..selection.end);
14260                        }
14261                    } else {
14262                        new_selection_ranges.push(selection.end..selection.end);
14263                    }
14264                }
14265            }
14266        }
14267        self.change_selections(Default::default(), window, cx, |s| {
14268            s.select_ranges(new_selection_ranges);
14269        });
14270    }
14271
14272    pub fn add_selection_above(
14273        &mut self,
14274        action: &AddSelectionAbove,
14275        window: &mut Window,
14276        cx: &mut Context<Self>,
14277    ) {
14278        self.add_selection(true, action.skip_soft_wrap, window, cx);
14279    }
14280
14281    pub fn add_selection_below(
14282        &mut self,
14283        action: &AddSelectionBelow,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) {
14287        self.add_selection(false, action.skip_soft_wrap, window, cx);
14288    }
14289
14290    fn add_selection(
14291        &mut self,
14292        above: bool,
14293        skip_soft_wrap: bool,
14294        window: &mut Window,
14295        cx: &mut Context<Self>,
14296    ) {
14297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14298
14299        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14300        let all_selections = self.selections.all::<Point>(&display_map);
14301        let text_layout_details = self.text_layout_details(window);
14302
14303        let (mut columnar_selections, new_selections_to_columnarize) = {
14304            if let Some(state) = self.add_selections_state.as_ref() {
14305                let columnar_selection_ids: HashSet<_> = state
14306                    .groups
14307                    .iter()
14308                    .flat_map(|group| group.stack.iter())
14309                    .copied()
14310                    .collect();
14311
14312                all_selections
14313                    .into_iter()
14314                    .partition(|s| columnar_selection_ids.contains(&s.id))
14315            } else {
14316                (Vec::new(), all_selections)
14317            }
14318        };
14319
14320        let mut state = self
14321            .add_selections_state
14322            .take()
14323            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14324
14325        for selection in new_selections_to_columnarize {
14326            let range = selection.display_range(&display_map).sorted();
14327            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14328            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14329            let positions = start_x.min(end_x)..start_x.max(end_x);
14330            let mut stack = Vec::new();
14331            for row in range.start.row().0..=range.end.row().0 {
14332                if let Some(selection) = self.selections.build_columnar_selection(
14333                    &display_map,
14334                    DisplayRow(row),
14335                    &positions,
14336                    selection.reversed,
14337                    &text_layout_details,
14338                ) {
14339                    stack.push(selection.id);
14340                    columnar_selections.push(selection);
14341                }
14342            }
14343            if !stack.is_empty() {
14344                if above {
14345                    stack.reverse();
14346                }
14347                state.groups.push(AddSelectionsGroup { above, stack });
14348            }
14349        }
14350
14351        let mut final_selections = Vec::new();
14352        let end_row = if above {
14353            DisplayRow(0)
14354        } else {
14355            display_map.max_point().row()
14356        };
14357
14358        let mut last_added_item_per_group = HashMap::default();
14359        for group in state.groups.iter_mut() {
14360            if let Some(last_id) = group.stack.last() {
14361                last_added_item_per_group.insert(*last_id, group);
14362            }
14363        }
14364
14365        for selection in columnar_selections {
14366            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14367                if above == group.above {
14368                    let range = selection.display_range(&display_map).sorted();
14369                    debug_assert_eq!(range.start.row(), range.end.row());
14370                    let mut row = range.start.row();
14371                    let positions =
14372                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14373                            Pixels::from(start)..Pixels::from(end)
14374                        } else {
14375                            let start_x =
14376                                display_map.x_for_display_point(range.start, &text_layout_details);
14377                            let end_x =
14378                                display_map.x_for_display_point(range.end, &text_layout_details);
14379                            start_x.min(end_x)..start_x.max(end_x)
14380                        };
14381
14382                    let mut maybe_new_selection = None;
14383                    let direction = if above { -1 } else { 1 };
14384
14385                    while row != end_row {
14386                        if skip_soft_wrap {
14387                            row = display_map
14388                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14389                                .row();
14390                        } else if above {
14391                            row.0 -= 1;
14392                        } else {
14393                            row.0 += 1;
14394                        }
14395
14396                        if let Some(new_selection) = self.selections.build_columnar_selection(
14397                            &display_map,
14398                            row,
14399                            &positions,
14400                            selection.reversed,
14401                            &text_layout_details,
14402                        ) {
14403                            maybe_new_selection = Some(new_selection);
14404                            break;
14405                        }
14406                    }
14407
14408                    if let Some(new_selection) = maybe_new_selection {
14409                        group.stack.push(new_selection.id);
14410                        if above {
14411                            final_selections.push(new_selection);
14412                            final_selections.push(selection);
14413                        } else {
14414                            final_selections.push(selection);
14415                            final_selections.push(new_selection);
14416                        }
14417                    } else {
14418                        final_selections.push(selection);
14419                    }
14420                } else {
14421                    group.stack.pop();
14422                }
14423            } else {
14424                final_selections.push(selection);
14425            }
14426        }
14427
14428        self.change_selections(Default::default(), window, cx, |s| {
14429            s.select(final_selections);
14430        });
14431
14432        let final_selection_ids: HashSet<_> = self
14433            .selections
14434            .all::<Point>(&display_map)
14435            .iter()
14436            .map(|s| s.id)
14437            .collect();
14438        state.groups.retain_mut(|group| {
14439            // selections might get merged above so we remove invalid items from stacks
14440            group.stack.retain(|id| final_selection_ids.contains(id));
14441
14442            // single selection in stack can be treated as initial state
14443            group.stack.len() > 1
14444        });
14445
14446        if !state.groups.is_empty() {
14447            self.add_selections_state = Some(state);
14448        }
14449    }
14450
14451    fn select_match_ranges(
14452        &mut self,
14453        range: Range<usize>,
14454        reversed: bool,
14455        replace_newest: bool,
14456        auto_scroll: Option<Autoscroll>,
14457        window: &mut Window,
14458        cx: &mut Context<Editor>,
14459    ) {
14460        self.unfold_ranges(
14461            std::slice::from_ref(&range),
14462            false,
14463            auto_scroll.is_some(),
14464            cx,
14465        );
14466        let effects = if let Some(scroll) = auto_scroll {
14467            SelectionEffects::scroll(scroll)
14468        } else {
14469            SelectionEffects::no_scroll()
14470        };
14471        self.change_selections(effects, window, cx, |s| {
14472            if replace_newest {
14473                s.delete(s.newest_anchor().id);
14474            }
14475            if reversed {
14476                s.insert_range(range.end..range.start);
14477            } else {
14478                s.insert_range(range);
14479            }
14480        });
14481    }
14482
14483    pub fn select_next_match_internal(
14484        &mut self,
14485        display_map: &DisplaySnapshot,
14486        replace_newest: bool,
14487        autoscroll: Option<Autoscroll>,
14488        window: &mut Window,
14489        cx: &mut Context<Self>,
14490    ) -> Result<()> {
14491        let buffer = display_map.buffer_snapshot();
14492        let mut selections = self.selections.all::<usize>(&display_map);
14493        if let Some(mut select_next_state) = self.select_next_state.take() {
14494            let query = &select_next_state.query;
14495            if !select_next_state.done {
14496                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14497                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14498                let mut next_selected_range = None;
14499
14500                // Collect and sort selection ranges for efficient overlap checking
14501                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14502                selection_ranges.sort_by_key(|r| r.start);
14503
14504                let bytes_after_last_selection =
14505                    buffer.bytes_in_range(last_selection.end..buffer.len());
14506                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14507                let query_matches = query
14508                    .stream_find_iter(bytes_after_last_selection)
14509                    .map(|result| (last_selection.end, result))
14510                    .chain(
14511                        query
14512                            .stream_find_iter(bytes_before_first_selection)
14513                            .map(|result| (0, result)),
14514                    );
14515
14516                for (start_offset, query_match) in query_matches {
14517                    let query_match = query_match.unwrap(); // can only fail due to I/O
14518                    let offset_range =
14519                        start_offset + query_match.start()..start_offset + query_match.end();
14520
14521                    if !select_next_state.wordwise
14522                        || (!buffer.is_inside_word(offset_range.start, None)
14523                            && !buffer.is_inside_word(offset_range.end, None))
14524                    {
14525                        // Use binary search to check for overlap (O(log n))
14526                        let overlaps = selection_ranges
14527                            .binary_search_by(|range| {
14528                                if range.end <= offset_range.start {
14529                                    std::cmp::Ordering::Less
14530                                } else if range.start >= offset_range.end {
14531                                    std::cmp::Ordering::Greater
14532                                } else {
14533                                    std::cmp::Ordering::Equal
14534                                }
14535                            })
14536                            .is_ok();
14537
14538                        if !overlaps {
14539                            next_selected_range = Some(offset_range);
14540                            break;
14541                        }
14542                    }
14543                }
14544
14545                if let Some(next_selected_range) = next_selected_range {
14546                    self.select_match_ranges(
14547                        next_selected_range,
14548                        last_selection.reversed,
14549                        replace_newest,
14550                        autoscroll,
14551                        window,
14552                        cx,
14553                    );
14554                } else {
14555                    select_next_state.done = true;
14556                }
14557            }
14558
14559            self.select_next_state = Some(select_next_state);
14560        } else {
14561            let mut only_carets = true;
14562            let mut same_text_selected = true;
14563            let mut selected_text = None;
14564
14565            let mut selections_iter = selections.iter().peekable();
14566            while let Some(selection) = selections_iter.next() {
14567                if selection.start != selection.end {
14568                    only_carets = false;
14569                }
14570
14571                if same_text_selected {
14572                    if selected_text.is_none() {
14573                        selected_text =
14574                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14575                    }
14576
14577                    if let Some(next_selection) = selections_iter.peek() {
14578                        if next_selection.range().len() == selection.range().len() {
14579                            let next_selected_text = buffer
14580                                .text_for_range(next_selection.range())
14581                                .collect::<String>();
14582                            if Some(next_selected_text) != selected_text {
14583                                same_text_selected = false;
14584                                selected_text = None;
14585                            }
14586                        } else {
14587                            same_text_selected = false;
14588                            selected_text = None;
14589                        }
14590                    }
14591                }
14592            }
14593
14594            if only_carets {
14595                for selection in &mut selections {
14596                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14597                    selection.start = word_range.start;
14598                    selection.end = word_range.end;
14599                    selection.goal = SelectionGoal::None;
14600                    selection.reversed = false;
14601                    self.select_match_ranges(
14602                        selection.start..selection.end,
14603                        selection.reversed,
14604                        replace_newest,
14605                        autoscroll,
14606                        window,
14607                        cx,
14608                    );
14609                }
14610
14611                if selections.len() == 1 {
14612                    let selection = selections
14613                        .last()
14614                        .expect("ensured that there's only one selection");
14615                    let query = buffer
14616                        .text_for_range(selection.start..selection.end)
14617                        .collect::<String>();
14618                    let is_empty = query.is_empty();
14619                    let select_state = SelectNextState {
14620                        query: AhoCorasick::new(&[query])?,
14621                        wordwise: true,
14622                        done: is_empty,
14623                    };
14624                    self.select_next_state = Some(select_state);
14625                } else {
14626                    self.select_next_state = None;
14627                }
14628            } else if let Some(selected_text) = selected_text {
14629                self.select_next_state = Some(SelectNextState {
14630                    query: AhoCorasick::new(&[selected_text])?,
14631                    wordwise: false,
14632                    done: false,
14633                });
14634                self.select_next_match_internal(
14635                    display_map,
14636                    replace_newest,
14637                    autoscroll,
14638                    window,
14639                    cx,
14640                )?;
14641            }
14642        }
14643        Ok(())
14644    }
14645
14646    pub fn select_all_matches(
14647        &mut self,
14648        _action: &SelectAllMatches,
14649        window: &mut Window,
14650        cx: &mut Context<Self>,
14651    ) -> Result<()> {
14652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14653
14654        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14655
14656        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14657        let Some(select_next_state) = self.select_next_state.as_mut() else {
14658            return Ok(());
14659        };
14660        if select_next_state.done {
14661            return Ok(());
14662        }
14663
14664        let mut new_selections = Vec::new();
14665
14666        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14667        let buffer = display_map.buffer_snapshot();
14668        let query_matches = select_next_state
14669            .query
14670            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14671
14672        for query_match in query_matches.into_iter() {
14673            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14674            let offset_range = if reversed {
14675                query_match.end()..query_match.start()
14676            } else {
14677                query_match.start()..query_match.end()
14678            };
14679
14680            if !select_next_state.wordwise
14681                || (!buffer.is_inside_word(offset_range.start, None)
14682                    && !buffer.is_inside_word(offset_range.end, None))
14683            {
14684                new_selections.push(offset_range.start..offset_range.end);
14685            }
14686        }
14687
14688        select_next_state.done = true;
14689
14690        if new_selections.is_empty() {
14691            log::error!("bug: new_selections is empty in select_all_matches");
14692            return Ok(());
14693        }
14694
14695        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14696        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14697            selections.select_ranges(new_selections)
14698        });
14699
14700        Ok(())
14701    }
14702
14703    pub fn select_next(
14704        &mut self,
14705        action: &SelectNext,
14706        window: &mut Window,
14707        cx: &mut Context<Self>,
14708    ) -> Result<()> {
14709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14710        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14711        self.select_next_match_internal(
14712            &display_map,
14713            action.replace_newest,
14714            Some(Autoscroll::newest()),
14715            window,
14716            cx,
14717        )?;
14718        Ok(())
14719    }
14720
14721    pub fn select_previous(
14722        &mut self,
14723        action: &SelectPrevious,
14724        window: &mut Window,
14725        cx: &mut Context<Self>,
14726    ) -> Result<()> {
14727        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14728        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14729        let buffer = display_map.buffer_snapshot();
14730        let mut selections = self.selections.all::<usize>(&display_map);
14731        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14732            let query = &select_prev_state.query;
14733            if !select_prev_state.done {
14734                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14735                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14736                let mut next_selected_range = None;
14737                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14738                let bytes_before_last_selection =
14739                    buffer.reversed_bytes_in_range(0..last_selection.start);
14740                let bytes_after_first_selection =
14741                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14742                let query_matches = query
14743                    .stream_find_iter(bytes_before_last_selection)
14744                    .map(|result| (last_selection.start, result))
14745                    .chain(
14746                        query
14747                            .stream_find_iter(bytes_after_first_selection)
14748                            .map(|result| (buffer.len(), result)),
14749                    );
14750                for (end_offset, query_match) in query_matches {
14751                    let query_match = query_match.unwrap(); // can only fail due to I/O
14752                    let offset_range =
14753                        end_offset - query_match.end()..end_offset - query_match.start();
14754
14755                    if !select_prev_state.wordwise
14756                        || (!buffer.is_inside_word(offset_range.start, None)
14757                            && !buffer.is_inside_word(offset_range.end, None))
14758                    {
14759                        next_selected_range = Some(offset_range);
14760                        break;
14761                    }
14762                }
14763
14764                if let Some(next_selected_range) = next_selected_range {
14765                    self.select_match_ranges(
14766                        next_selected_range,
14767                        last_selection.reversed,
14768                        action.replace_newest,
14769                        Some(Autoscroll::newest()),
14770                        window,
14771                        cx,
14772                    );
14773                } else {
14774                    select_prev_state.done = true;
14775                }
14776            }
14777
14778            self.select_prev_state = Some(select_prev_state);
14779        } else {
14780            let mut only_carets = true;
14781            let mut same_text_selected = true;
14782            let mut selected_text = None;
14783
14784            let mut selections_iter = selections.iter().peekable();
14785            while let Some(selection) = selections_iter.next() {
14786                if selection.start != selection.end {
14787                    only_carets = false;
14788                }
14789
14790                if same_text_selected {
14791                    if selected_text.is_none() {
14792                        selected_text =
14793                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14794                    }
14795
14796                    if let Some(next_selection) = selections_iter.peek() {
14797                        if next_selection.range().len() == selection.range().len() {
14798                            let next_selected_text = buffer
14799                                .text_for_range(next_selection.range())
14800                                .collect::<String>();
14801                            if Some(next_selected_text) != selected_text {
14802                                same_text_selected = false;
14803                                selected_text = None;
14804                            }
14805                        } else {
14806                            same_text_selected = false;
14807                            selected_text = None;
14808                        }
14809                    }
14810                }
14811            }
14812
14813            if only_carets {
14814                for selection in &mut selections {
14815                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14816                    selection.start = word_range.start;
14817                    selection.end = word_range.end;
14818                    selection.goal = SelectionGoal::None;
14819                    selection.reversed = false;
14820                    self.select_match_ranges(
14821                        selection.start..selection.end,
14822                        selection.reversed,
14823                        action.replace_newest,
14824                        Some(Autoscroll::newest()),
14825                        window,
14826                        cx,
14827                    );
14828                }
14829                if selections.len() == 1 {
14830                    let selection = selections
14831                        .last()
14832                        .expect("ensured that there's only one selection");
14833                    let query = buffer
14834                        .text_for_range(selection.start..selection.end)
14835                        .collect::<String>();
14836                    let is_empty = query.is_empty();
14837                    let select_state = SelectNextState {
14838                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14839                        wordwise: true,
14840                        done: is_empty,
14841                    };
14842                    self.select_prev_state = Some(select_state);
14843                } else {
14844                    self.select_prev_state = None;
14845                }
14846            } else if let Some(selected_text) = selected_text {
14847                self.select_prev_state = Some(SelectNextState {
14848                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14849                    wordwise: false,
14850                    done: false,
14851                });
14852                self.select_previous(action, window, cx)?;
14853            }
14854        }
14855        Ok(())
14856    }
14857
14858    pub fn find_next_match(
14859        &mut self,
14860        _: &FindNextMatch,
14861        window: &mut Window,
14862        cx: &mut Context<Self>,
14863    ) -> Result<()> {
14864        let selections = self.selections.disjoint_anchors_arc();
14865        match selections.first() {
14866            Some(first) if selections.len() >= 2 => {
14867                self.change_selections(Default::default(), window, cx, |s| {
14868                    s.select_ranges([first.range()]);
14869                });
14870            }
14871            _ => self.select_next(
14872                &SelectNext {
14873                    replace_newest: true,
14874                },
14875                window,
14876                cx,
14877            )?,
14878        }
14879        Ok(())
14880    }
14881
14882    pub fn find_previous_match(
14883        &mut self,
14884        _: &FindPreviousMatch,
14885        window: &mut Window,
14886        cx: &mut Context<Self>,
14887    ) -> Result<()> {
14888        let selections = self.selections.disjoint_anchors_arc();
14889        match selections.last() {
14890            Some(last) if selections.len() >= 2 => {
14891                self.change_selections(Default::default(), window, cx, |s| {
14892                    s.select_ranges([last.range()]);
14893                });
14894            }
14895            _ => self.select_previous(
14896                &SelectPrevious {
14897                    replace_newest: true,
14898                },
14899                window,
14900                cx,
14901            )?,
14902        }
14903        Ok(())
14904    }
14905
14906    pub fn toggle_comments(
14907        &mut self,
14908        action: &ToggleComments,
14909        window: &mut Window,
14910        cx: &mut Context<Self>,
14911    ) {
14912        if self.read_only(cx) {
14913            return;
14914        }
14915        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14916        let text_layout_details = &self.text_layout_details(window);
14917        self.transact(window, cx, |this, window, cx| {
14918            let mut selections = this
14919                .selections
14920                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14921            let mut edits = Vec::new();
14922            let mut selection_edit_ranges = Vec::new();
14923            let mut last_toggled_row = None;
14924            let snapshot = this.buffer.read(cx).read(cx);
14925            let empty_str: Arc<str> = Arc::default();
14926            let mut suffixes_inserted = Vec::new();
14927            let ignore_indent = action.ignore_indent;
14928
14929            fn comment_prefix_range(
14930                snapshot: &MultiBufferSnapshot,
14931                row: MultiBufferRow,
14932                comment_prefix: &str,
14933                comment_prefix_whitespace: &str,
14934                ignore_indent: bool,
14935            ) -> Range<Point> {
14936                let indent_size = if ignore_indent {
14937                    0
14938                } else {
14939                    snapshot.indent_size_for_line(row).len
14940                };
14941
14942                let start = Point::new(row.0, indent_size);
14943
14944                let mut line_bytes = snapshot
14945                    .bytes_in_range(start..snapshot.max_point())
14946                    .flatten()
14947                    .copied();
14948
14949                // If this line currently begins with the line comment prefix, then record
14950                // the range containing the prefix.
14951                if line_bytes
14952                    .by_ref()
14953                    .take(comment_prefix.len())
14954                    .eq(comment_prefix.bytes())
14955                {
14956                    // Include any whitespace that matches the comment prefix.
14957                    let matching_whitespace_len = line_bytes
14958                        .zip(comment_prefix_whitespace.bytes())
14959                        .take_while(|(a, b)| a == b)
14960                        .count() as u32;
14961                    let end = Point::new(
14962                        start.row,
14963                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14964                    );
14965                    start..end
14966                } else {
14967                    start..start
14968                }
14969            }
14970
14971            fn comment_suffix_range(
14972                snapshot: &MultiBufferSnapshot,
14973                row: MultiBufferRow,
14974                comment_suffix: &str,
14975                comment_suffix_has_leading_space: bool,
14976            ) -> Range<Point> {
14977                let end = Point::new(row.0, snapshot.line_len(row));
14978                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14979
14980                let mut line_end_bytes = snapshot
14981                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14982                    .flatten()
14983                    .copied();
14984
14985                let leading_space_len = if suffix_start_column > 0
14986                    && line_end_bytes.next() == Some(b' ')
14987                    && comment_suffix_has_leading_space
14988                {
14989                    1
14990                } else {
14991                    0
14992                };
14993
14994                // If this line currently begins with the line comment prefix, then record
14995                // the range containing the prefix.
14996                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14997                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14998                    start..end
14999                } else {
15000                    end..end
15001                }
15002            }
15003
15004            // TODO: Handle selections that cross excerpts
15005            for selection in &mut selections {
15006                let start_column = snapshot
15007                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15008                    .len;
15009                let language = if let Some(language) =
15010                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15011                {
15012                    language
15013                } else {
15014                    continue;
15015                };
15016
15017                selection_edit_ranges.clear();
15018
15019                // If multiple selections contain a given row, avoid processing that
15020                // row more than once.
15021                let mut start_row = MultiBufferRow(selection.start.row);
15022                if last_toggled_row == Some(start_row) {
15023                    start_row = start_row.next_row();
15024                }
15025                let end_row =
15026                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15027                        MultiBufferRow(selection.end.row - 1)
15028                    } else {
15029                        MultiBufferRow(selection.end.row)
15030                    };
15031                last_toggled_row = Some(end_row);
15032
15033                if start_row > end_row {
15034                    continue;
15035                }
15036
15037                // If the language has line comments, toggle those.
15038                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15039
15040                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15041                if ignore_indent {
15042                    full_comment_prefixes = full_comment_prefixes
15043                        .into_iter()
15044                        .map(|s| Arc::from(s.trim_end()))
15045                        .collect();
15046                }
15047
15048                if !full_comment_prefixes.is_empty() {
15049                    let first_prefix = full_comment_prefixes
15050                        .first()
15051                        .expect("prefixes is non-empty");
15052                    let prefix_trimmed_lengths = full_comment_prefixes
15053                        .iter()
15054                        .map(|p| p.trim_end_matches(' ').len())
15055                        .collect::<SmallVec<[usize; 4]>>();
15056
15057                    let mut all_selection_lines_are_comments = true;
15058
15059                    for row in start_row.0..=end_row.0 {
15060                        let row = MultiBufferRow(row);
15061                        if start_row < end_row && snapshot.is_line_blank(row) {
15062                            continue;
15063                        }
15064
15065                        let prefix_range = full_comment_prefixes
15066                            .iter()
15067                            .zip(prefix_trimmed_lengths.iter().copied())
15068                            .map(|(prefix, trimmed_prefix_len)| {
15069                                comment_prefix_range(
15070                                    snapshot.deref(),
15071                                    row,
15072                                    &prefix[..trimmed_prefix_len],
15073                                    &prefix[trimmed_prefix_len..],
15074                                    ignore_indent,
15075                                )
15076                            })
15077                            .max_by_key(|range| range.end.column - range.start.column)
15078                            .expect("prefixes is non-empty");
15079
15080                        if prefix_range.is_empty() {
15081                            all_selection_lines_are_comments = false;
15082                        }
15083
15084                        selection_edit_ranges.push(prefix_range);
15085                    }
15086
15087                    if all_selection_lines_are_comments {
15088                        edits.extend(
15089                            selection_edit_ranges
15090                                .iter()
15091                                .cloned()
15092                                .map(|range| (range, empty_str.clone())),
15093                        );
15094                    } else {
15095                        let min_column = selection_edit_ranges
15096                            .iter()
15097                            .map(|range| range.start.column)
15098                            .min()
15099                            .unwrap_or(0);
15100                        edits.extend(selection_edit_ranges.iter().map(|range| {
15101                            let position = Point::new(range.start.row, min_column);
15102                            (position..position, first_prefix.clone())
15103                        }));
15104                    }
15105                } else if let Some(BlockCommentConfig {
15106                    start: full_comment_prefix,
15107                    end: comment_suffix,
15108                    ..
15109                }) = language.block_comment()
15110                {
15111                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15112                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15113                    let prefix_range = comment_prefix_range(
15114                        snapshot.deref(),
15115                        start_row,
15116                        comment_prefix,
15117                        comment_prefix_whitespace,
15118                        ignore_indent,
15119                    );
15120                    let suffix_range = comment_suffix_range(
15121                        snapshot.deref(),
15122                        end_row,
15123                        comment_suffix.trim_start_matches(' '),
15124                        comment_suffix.starts_with(' '),
15125                    );
15126
15127                    if prefix_range.is_empty() || suffix_range.is_empty() {
15128                        edits.push((
15129                            prefix_range.start..prefix_range.start,
15130                            full_comment_prefix.clone(),
15131                        ));
15132                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15133                        suffixes_inserted.push((end_row, comment_suffix.len()));
15134                    } else {
15135                        edits.push((prefix_range, empty_str.clone()));
15136                        edits.push((suffix_range, empty_str.clone()));
15137                    }
15138                } else {
15139                    continue;
15140                }
15141            }
15142
15143            drop(snapshot);
15144            this.buffer.update(cx, |buffer, cx| {
15145                buffer.edit(edits, None, cx);
15146            });
15147
15148            // Adjust selections so that they end before any comment suffixes that
15149            // were inserted.
15150            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15151            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15152            let snapshot = this.buffer.read(cx).read(cx);
15153            for selection in &mut selections {
15154                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15155                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15156                        Ordering::Less => {
15157                            suffixes_inserted.next();
15158                            continue;
15159                        }
15160                        Ordering::Greater => break,
15161                        Ordering::Equal => {
15162                            if selection.end.column == snapshot.line_len(row) {
15163                                if selection.is_empty() {
15164                                    selection.start.column -= suffix_len as u32;
15165                                }
15166                                selection.end.column -= suffix_len as u32;
15167                            }
15168                            break;
15169                        }
15170                    }
15171                }
15172            }
15173
15174            drop(snapshot);
15175            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15176
15177            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15178            let selections_on_single_row = selections.windows(2).all(|selections| {
15179                selections[0].start.row == selections[1].start.row
15180                    && selections[0].end.row == selections[1].end.row
15181                    && selections[0].start.row == selections[0].end.row
15182            });
15183            let selections_selecting = selections
15184                .iter()
15185                .any(|selection| selection.start != selection.end);
15186            let advance_downwards = action.advance_downwards
15187                && selections_on_single_row
15188                && !selections_selecting
15189                && !matches!(this.mode, EditorMode::SingleLine);
15190
15191            if advance_downwards {
15192                let snapshot = this.buffer.read(cx).snapshot(cx);
15193
15194                this.change_selections(Default::default(), window, cx, |s| {
15195                    s.move_cursors_with(|display_snapshot, display_point, _| {
15196                        let mut point = display_point.to_point(display_snapshot);
15197                        point.row += 1;
15198                        point = snapshot.clip_point(point, Bias::Left);
15199                        let display_point = point.to_display_point(display_snapshot);
15200                        let goal = SelectionGoal::HorizontalPosition(
15201                            display_snapshot
15202                                .x_for_display_point(display_point, text_layout_details)
15203                                .into(),
15204                        );
15205                        (display_point, goal)
15206                    })
15207                });
15208            }
15209        });
15210    }
15211
15212    pub fn select_enclosing_symbol(
15213        &mut self,
15214        _: &SelectEnclosingSymbol,
15215        window: &mut Window,
15216        cx: &mut Context<Self>,
15217    ) {
15218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15219
15220        let buffer = self.buffer.read(cx).snapshot(cx);
15221        let old_selections = self
15222            .selections
15223            .all::<usize>(&self.display_snapshot(cx))
15224            .into_boxed_slice();
15225
15226        fn update_selection(
15227            selection: &Selection<usize>,
15228            buffer_snap: &MultiBufferSnapshot,
15229        ) -> Option<Selection<usize>> {
15230            let cursor = selection.head();
15231            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15232            for symbol in symbols.iter().rev() {
15233                let start = symbol.range.start.to_offset(buffer_snap);
15234                let end = symbol.range.end.to_offset(buffer_snap);
15235                let new_range = start..end;
15236                if start < selection.start || end > selection.end {
15237                    return Some(Selection {
15238                        id: selection.id,
15239                        start: new_range.start,
15240                        end: new_range.end,
15241                        goal: SelectionGoal::None,
15242                        reversed: selection.reversed,
15243                    });
15244                }
15245            }
15246            None
15247        }
15248
15249        let mut selected_larger_symbol = false;
15250        let new_selections = old_selections
15251            .iter()
15252            .map(|selection| match update_selection(selection, &buffer) {
15253                Some(new_selection) => {
15254                    if new_selection.range() != selection.range() {
15255                        selected_larger_symbol = true;
15256                    }
15257                    new_selection
15258                }
15259                None => selection.clone(),
15260            })
15261            .collect::<Vec<_>>();
15262
15263        if selected_larger_symbol {
15264            self.change_selections(Default::default(), window, cx, |s| {
15265                s.select(new_selections);
15266            });
15267        }
15268    }
15269
15270    pub fn select_larger_syntax_node(
15271        &mut self,
15272        _: &SelectLargerSyntaxNode,
15273        window: &mut Window,
15274        cx: &mut Context<Self>,
15275    ) {
15276        let Some(visible_row_count) = self.visible_row_count() else {
15277            return;
15278        };
15279        let old_selections: Box<[_]> = self
15280            .selections
15281            .all::<usize>(&self.display_snapshot(cx))
15282            .into();
15283        if old_selections.is_empty() {
15284            return;
15285        }
15286
15287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15288
15289        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15290        let buffer = self.buffer.read(cx).snapshot(cx);
15291
15292        let mut selected_larger_node = false;
15293        let mut new_selections = old_selections
15294            .iter()
15295            .map(|selection| {
15296                let old_range = selection.start..selection.end;
15297
15298                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15299                    // manually select word at selection
15300                    if ["string_content", "inline"].contains(&node.kind()) {
15301                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15302                        // ignore if word is already selected
15303                        if !word_range.is_empty() && old_range != word_range {
15304                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15305                            // only select word if start and end point belongs to same word
15306                            if word_range == last_word_range {
15307                                selected_larger_node = true;
15308                                return Selection {
15309                                    id: selection.id,
15310                                    start: word_range.start,
15311                                    end: word_range.end,
15312                                    goal: SelectionGoal::None,
15313                                    reversed: selection.reversed,
15314                                };
15315                            }
15316                        }
15317                    }
15318                }
15319
15320                let mut new_range = old_range.clone();
15321                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15322                    new_range = range;
15323                    if !node.is_named() {
15324                        continue;
15325                    }
15326                    if !display_map.intersects_fold(new_range.start)
15327                        && !display_map.intersects_fold(new_range.end)
15328                    {
15329                        break;
15330                    }
15331                }
15332
15333                selected_larger_node |= new_range != old_range;
15334                Selection {
15335                    id: selection.id,
15336                    start: new_range.start,
15337                    end: new_range.end,
15338                    goal: SelectionGoal::None,
15339                    reversed: selection.reversed,
15340                }
15341            })
15342            .collect::<Vec<_>>();
15343
15344        if !selected_larger_node {
15345            return; // don't put this call in the history
15346        }
15347
15348        // scroll based on transformation done to the last selection created by the user
15349        let (last_old, last_new) = old_selections
15350            .last()
15351            .zip(new_selections.last().cloned())
15352            .expect("old_selections isn't empty");
15353
15354        // revert selection
15355        let is_selection_reversed = {
15356            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15357            new_selections.last_mut().expect("checked above").reversed =
15358                should_newest_selection_be_reversed;
15359            should_newest_selection_be_reversed
15360        };
15361
15362        if selected_larger_node {
15363            self.select_syntax_node_history.disable_clearing = true;
15364            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15365                s.select(new_selections.clone());
15366            });
15367            self.select_syntax_node_history.disable_clearing = false;
15368        }
15369
15370        let start_row = last_new.start.to_display_point(&display_map).row().0;
15371        let end_row = last_new.end.to_display_point(&display_map).row().0;
15372        let selection_height = end_row - start_row + 1;
15373        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15374
15375        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15376        let scroll_behavior = if fits_on_the_screen {
15377            self.request_autoscroll(Autoscroll::fit(), cx);
15378            SelectSyntaxNodeScrollBehavior::FitSelection
15379        } else if is_selection_reversed {
15380            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15381            SelectSyntaxNodeScrollBehavior::CursorTop
15382        } else {
15383            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15384            SelectSyntaxNodeScrollBehavior::CursorBottom
15385        };
15386
15387        self.select_syntax_node_history.push((
15388            old_selections,
15389            scroll_behavior,
15390            is_selection_reversed,
15391        ));
15392    }
15393
15394    pub fn select_smaller_syntax_node(
15395        &mut self,
15396        _: &SelectSmallerSyntaxNode,
15397        window: &mut Window,
15398        cx: &mut Context<Self>,
15399    ) {
15400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15401
15402        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15403            self.select_syntax_node_history.pop()
15404        {
15405            if let Some(selection) = selections.last_mut() {
15406                selection.reversed = is_selection_reversed;
15407            }
15408
15409            self.select_syntax_node_history.disable_clearing = true;
15410            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15411                s.select(selections.to_vec());
15412            });
15413            self.select_syntax_node_history.disable_clearing = false;
15414
15415            match scroll_behavior {
15416                SelectSyntaxNodeScrollBehavior::CursorTop => {
15417                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15418                }
15419                SelectSyntaxNodeScrollBehavior::FitSelection => {
15420                    self.request_autoscroll(Autoscroll::fit(), cx);
15421                }
15422                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15423                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15424                }
15425            }
15426        }
15427    }
15428
15429    pub fn unwrap_syntax_node(
15430        &mut self,
15431        _: &UnwrapSyntaxNode,
15432        window: &mut Window,
15433        cx: &mut Context<Self>,
15434    ) {
15435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15436
15437        let buffer = self.buffer.read(cx).snapshot(cx);
15438        let selections = self
15439            .selections
15440            .all::<usize>(&self.display_snapshot(cx))
15441            .into_iter()
15442            // subtracting the offset requires sorting
15443            .sorted_by_key(|i| i.start);
15444
15445        let full_edits = selections
15446            .into_iter()
15447            .filter_map(|selection| {
15448                let child = if selection.is_empty()
15449                    && let Some((_, ancestor_range)) =
15450                        buffer.syntax_ancestor(selection.start..selection.end)
15451                {
15452                    ancestor_range
15453                } else {
15454                    selection.range()
15455                };
15456
15457                let mut parent = child.clone();
15458                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15459                    parent = ancestor_range;
15460                    if parent.start < child.start || parent.end > child.end {
15461                        break;
15462                    }
15463                }
15464
15465                if parent == child {
15466                    return None;
15467                }
15468                let text = buffer.text_for_range(child).collect::<String>();
15469                Some((selection.id, parent, text))
15470            })
15471            .collect::<Vec<_>>();
15472        if full_edits.is_empty() {
15473            return;
15474        }
15475
15476        self.transact(window, cx, |this, window, cx| {
15477            this.buffer.update(cx, |buffer, cx| {
15478                buffer.edit(
15479                    full_edits
15480                        .iter()
15481                        .map(|(_, p, t)| (p.clone(), t.clone()))
15482                        .collect::<Vec<_>>(),
15483                    None,
15484                    cx,
15485                );
15486            });
15487            this.change_selections(Default::default(), window, cx, |s| {
15488                let mut offset = 0;
15489                let mut selections = vec![];
15490                for (id, parent, text) in full_edits {
15491                    let start = parent.start - offset;
15492                    offset += parent.len() - text.len();
15493                    selections.push(Selection {
15494                        id,
15495                        start,
15496                        end: start + text.len(),
15497                        reversed: false,
15498                        goal: Default::default(),
15499                    });
15500                }
15501                s.select(selections);
15502            });
15503        });
15504    }
15505
15506    pub fn select_next_syntax_node(
15507        &mut self,
15508        _: &SelectNextSyntaxNode,
15509        window: &mut Window,
15510        cx: &mut Context<Self>,
15511    ) {
15512        let old_selections: Box<[_]> = self
15513            .selections
15514            .all::<usize>(&self.display_snapshot(cx))
15515            .into();
15516        if old_selections.is_empty() {
15517            return;
15518        }
15519
15520        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15521
15522        let buffer = self.buffer.read(cx).snapshot(cx);
15523        let mut selected_sibling = false;
15524
15525        let new_selections = old_selections
15526            .iter()
15527            .map(|selection| {
15528                let old_range = selection.start..selection.end;
15529
15530                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15531                    let new_range = node.byte_range();
15532                    selected_sibling = true;
15533                    Selection {
15534                        id: selection.id,
15535                        start: new_range.start,
15536                        end: new_range.end,
15537                        goal: SelectionGoal::None,
15538                        reversed: selection.reversed,
15539                    }
15540                } else {
15541                    selection.clone()
15542                }
15543            })
15544            .collect::<Vec<_>>();
15545
15546        if selected_sibling {
15547            self.change_selections(
15548                SelectionEffects::scroll(Autoscroll::fit()),
15549                window,
15550                cx,
15551                |s| {
15552                    s.select(new_selections);
15553                },
15554            );
15555        }
15556    }
15557
15558    pub fn select_prev_syntax_node(
15559        &mut self,
15560        _: &SelectPreviousSyntaxNode,
15561        window: &mut Window,
15562        cx: &mut Context<Self>,
15563    ) {
15564        let old_selections: Box<[_]> = self
15565            .selections
15566            .all::<usize>(&self.display_snapshot(cx))
15567            .into();
15568        if old_selections.is_empty() {
15569            return;
15570        }
15571
15572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15573
15574        let buffer = self.buffer.read(cx).snapshot(cx);
15575        let mut selected_sibling = false;
15576
15577        let new_selections = old_selections
15578            .iter()
15579            .map(|selection| {
15580                let old_range = selection.start..selection.end;
15581
15582                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15583                    let new_range = node.byte_range();
15584                    selected_sibling = true;
15585                    Selection {
15586                        id: selection.id,
15587                        start: new_range.start,
15588                        end: new_range.end,
15589                        goal: SelectionGoal::None,
15590                        reversed: selection.reversed,
15591                    }
15592                } else {
15593                    selection.clone()
15594                }
15595            })
15596            .collect::<Vec<_>>();
15597
15598        if selected_sibling {
15599            self.change_selections(
15600                SelectionEffects::scroll(Autoscroll::fit()),
15601                window,
15602                cx,
15603                |s| {
15604                    s.select(new_selections);
15605                },
15606            );
15607        }
15608    }
15609
15610    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15611        if !EditorSettings::get_global(cx).gutter.runnables {
15612            self.clear_tasks();
15613            return Task::ready(());
15614        }
15615        let project = self.project().map(Entity::downgrade);
15616        let task_sources = self.lsp_task_sources(cx);
15617        let multi_buffer = self.buffer.downgrade();
15618        cx.spawn_in(window, async move |editor, cx| {
15619            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15620            let Some(project) = project.and_then(|p| p.upgrade()) else {
15621                return;
15622            };
15623            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15624                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15625            }) else {
15626                return;
15627            };
15628
15629            let hide_runnables = project
15630                .update(cx, |project, _| project.is_via_collab())
15631                .unwrap_or(true);
15632            if hide_runnables {
15633                return;
15634            }
15635            let new_rows =
15636                cx.background_spawn({
15637                    let snapshot = display_snapshot.clone();
15638                    async move {
15639                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15640                    }
15641                })
15642                    .await;
15643            let Ok(lsp_tasks) =
15644                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15645            else {
15646                return;
15647            };
15648            let lsp_tasks = lsp_tasks.await;
15649
15650            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15651                lsp_tasks
15652                    .into_iter()
15653                    .flat_map(|(kind, tasks)| {
15654                        tasks.into_iter().filter_map(move |(location, task)| {
15655                            Some((kind.clone(), location?, task))
15656                        })
15657                    })
15658                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15659                        let buffer = location.target.buffer;
15660                        let buffer_snapshot = buffer.read(cx).snapshot();
15661                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15662                            |(excerpt_id, snapshot, _)| {
15663                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15664                                    display_snapshot
15665                                        .buffer_snapshot()
15666                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15667                                } else {
15668                                    None
15669                                }
15670                            },
15671                        );
15672                        if let Some(offset) = offset {
15673                            let task_buffer_range =
15674                                location.target.range.to_point(&buffer_snapshot);
15675                            let context_buffer_range =
15676                                task_buffer_range.to_offset(&buffer_snapshot);
15677                            let context_range = BufferOffset(context_buffer_range.start)
15678                                ..BufferOffset(context_buffer_range.end);
15679
15680                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15681                                .or_insert_with(|| RunnableTasks {
15682                                    templates: Vec::new(),
15683                                    offset,
15684                                    column: task_buffer_range.start.column,
15685                                    extra_variables: HashMap::default(),
15686                                    context_range,
15687                                })
15688                                .templates
15689                                .push((kind, task.original_task().clone()));
15690                        }
15691
15692                        acc
15693                    })
15694            }) else {
15695                return;
15696            };
15697
15698            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15699                buffer.language_settings(cx).tasks.prefer_lsp
15700            }) else {
15701                return;
15702            };
15703
15704            let rows = Self::runnable_rows(
15705                project,
15706                display_snapshot,
15707                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15708                new_rows,
15709                cx.clone(),
15710            )
15711            .await;
15712            editor
15713                .update(cx, |editor, _| {
15714                    editor.clear_tasks();
15715                    for (key, mut value) in rows {
15716                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15717                            value.templates.extend(lsp_tasks.templates);
15718                        }
15719
15720                        editor.insert_tasks(key, value);
15721                    }
15722                    for (key, value) in lsp_tasks_by_rows {
15723                        editor.insert_tasks(key, value);
15724                    }
15725                })
15726                .ok();
15727        })
15728    }
15729    fn fetch_runnable_ranges(
15730        snapshot: &DisplaySnapshot,
15731        range: Range<Anchor>,
15732    ) -> Vec<language::RunnableRange> {
15733        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15734    }
15735
15736    fn runnable_rows(
15737        project: Entity<Project>,
15738        snapshot: DisplaySnapshot,
15739        prefer_lsp: bool,
15740        runnable_ranges: Vec<RunnableRange>,
15741        cx: AsyncWindowContext,
15742    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15743        cx.spawn(async move |cx| {
15744            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15745            for mut runnable in runnable_ranges {
15746                let Some(tasks) = cx
15747                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15748                    .ok()
15749                else {
15750                    continue;
15751                };
15752                let mut tasks = tasks.await;
15753
15754                if prefer_lsp {
15755                    tasks.retain(|(task_kind, _)| {
15756                        !matches!(task_kind, TaskSourceKind::Language { .. })
15757                    });
15758                }
15759                if tasks.is_empty() {
15760                    continue;
15761                }
15762
15763                let point = runnable
15764                    .run_range
15765                    .start
15766                    .to_point(&snapshot.buffer_snapshot());
15767                let Some(row) = snapshot
15768                    .buffer_snapshot()
15769                    .buffer_line_for_row(MultiBufferRow(point.row))
15770                    .map(|(_, range)| range.start.row)
15771                else {
15772                    continue;
15773                };
15774
15775                let context_range =
15776                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15777                runnable_rows.push((
15778                    (runnable.buffer_id, row),
15779                    RunnableTasks {
15780                        templates: tasks,
15781                        offset: snapshot
15782                            .buffer_snapshot()
15783                            .anchor_before(runnable.run_range.start),
15784                        context_range,
15785                        column: point.column,
15786                        extra_variables: runnable.extra_captures,
15787                    },
15788                ));
15789            }
15790            runnable_rows
15791        })
15792    }
15793
15794    fn templates_with_tags(
15795        project: &Entity<Project>,
15796        runnable: &mut Runnable,
15797        cx: &mut App,
15798    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15799        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15800            let (worktree_id, file) = project
15801                .buffer_for_id(runnable.buffer, cx)
15802                .and_then(|buffer| buffer.read(cx).file())
15803                .map(|file| (file.worktree_id(cx), file.clone()))
15804                .unzip();
15805
15806            (
15807                project.task_store().read(cx).task_inventory().cloned(),
15808                worktree_id,
15809                file,
15810            )
15811        });
15812
15813        let tags = mem::take(&mut runnable.tags);
15814        let language = runnable.language.clone();
15815        cx.spawn(async move |cx| {
15816            let mut templates_with_tags = Vec::new();
15817            if let Some(inventory) = inventory {
15818                for RunnableTag(tag) in tags {
15819                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15820                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15821                    }) else {
15822                        return templates_with_tags;
15823                    };
15824                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15825                        move |(_, template)| {
15826                            template.tags.iter().any(|source_tag| source_tag == &tag)
15827                        },
15828                    ));
15829                }
15830            }
15831            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15832
15833            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15834                // Strongest source wins; if we have worktree tag binding, prefer that to
15835                // global and language bindings;
15836                // if we have a global binding, prefer that to language binding.
15837                let first_mismatch = templates_with_tags
15838                    .iter()
15839                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15840                if let Some(index) = first_mismatch {
15841                    templates_with_tags.truncate(index);
15842                }
15843            }
15844
15845            templates_with_tags
15846        })
15847    }
15848
15849    pub fn move_to_enclosing_bracket(
15850        &mut self,
15851        _: &MoveToEnclosingBracket,
15852        window: &mut Window,
15853        cx: &mut Context<Self>,
15854    ) {
15855        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15856        self.change_selections(Default::default(), window, cx, |s| {
15857            s.move_offsets_with(|snapshot, selection| {
15858                let Some(enclosing_bracket_ranges) =
15859                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15860                else {
15861                    return;
15862                };
15863
15864                let mut best_length = usize::MAX;
15865                let mut best_inside = false;
15866                let mut best_in_bracket_range = false;
15867                let mut best_destination = None;
15868                for (open, close) in enclosing_bracket_ranges {
15869                    let close = close.to_inclusive();
15870                    let length = close.end() - open.start;
15871                    let inside = selection.start >= open.end && selection.end <= *close.start();
15872                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15873                        || close.contains(&selection.head());
15874
15875                    // If best is next to a bracket and current isn't, skip
15876                    if !in_bracket_range && best_in_bracket_range {
15877                        continue;
15878                    }
15879
15880                    // Prefer smaller lengths unless best is inside and current isn't
15881                    if length > best_length && (best_inside || !inside) {
15882                        continue;
15883                    }
15884
15885                    best_length = length;
15886                    best_inside = inside;
15887                    best_in_bracket_range = in_bracket_range;
15888                    best_destination = Some(
15889                        if close.contains(&selection.start) && close.contains(&selection.end) {
15890                            if inside { open.end } else { open.start }
15891                        } else if inside {
15892                            *close.start()
15893                        } else {
15894                            *close.end()
15895                        },
15896                    );
15897                }
15898
15899                if let Some(destination) = best_destination {
15900                    selection.collapse_to(destination, SelectionGoal::None);
15901                }
15902            })
15903        });
15904    }
15905
15906    pub fn undo_selection(
15907        &mut self,
15908        _: &UndoSelection,
15909        window: &mut Window,
15910        cx: &mut Context<Self>,
15911    ) {
15912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15913        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15914            self.selection_history.mode = SelectionHistoryMode::Undoing;
15915            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15916                this.end_selection(window, cx);
15917                this.change_selections(
15918                    SelectionEffects::scroll(Autoscroll::newest()),
15919                    window,
15920                    cx,
15921                    |s| s.select_anchors(entry.selections.to_vec()),
15922                );
15923            });
15924            self.selection_history.mode = SelectionHistoryMode::Normal;
15925
15926            self.select_next_state = entry.select_next_state;
15927            self.select_prev_state = entry.select_prev_state;
15928            self.add_selections_state = entry.add_selections_state;
15929        }
15930    }
15931
15932    pub fn redo_selection(
15933        &mut self,
15934        _: &RedoSelection,
15935        window: &mut Window,
15936        cx: &mut Context<Self>,
15937    ) {
15938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15939        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15940            self.selection_history.mode = SelectionHistoryMode::Redoing;
15941            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15942                this.end_selection(window, cx);
15943                this.change_selections(
15944                    SelectionEffects::scroll(Autoscroll::newest()),
15945                    window,
15946                    cx,
15947                    |s| s.select_anchors(entry.selections.to_vec()),
15948                );
15949            });
15950            self.selection_history.mode = SelectionHistoryMode::Normal;
15951
15952            self.select_next_state = entry.select_next_state;
15953            self.select_prev_state = entry.select_prev_state;
15954            self.add_selections_state = entry.add_selections_state;
15955        }
15956    }
15957
15958    pub fn expand_excerpts(
15959        &mut self,
15960        action: &ExpandExcerpts,
15961        _: &mut Window,
15962        cx: &mut Context<Self>,
15963    ) {
15964        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15965    }
15966
15967    pub fn expand_excerpts_down(
15968        &mut self,
15969        action: &ExpandExcerptsDown,
15970        _: &mut Window,
15971        cx: &mut Context<Self>,
15972    ) {
15973        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15974    }
15975
15976    pub fn expand_excerpts_up(
15977        &mut self,
15978        action: &ExpandExcerptsUp,
15979        _: &mut Window,
15980        cx: &mut Context<Self>,
15981    ) {
15982        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15983    }
15984
15985    pub fn expand_excerpts_for_direction(
15986        &mut self,
15987        lines: u32,
15988        direction: ExpandExcerptDirection,
15989
15990        cx: &mut Context<Self>,
15991    ) {
15992        let selections = self.selections.disjoint_anchors_arc();
15993
15994        let lines = if lines == 0 {
15995            EditorSettings::get_global(cx).expand_excerpt_lines
15996        } else {
15997            lines
15998        };
15999
16000        self.buffer.update(cx, |buffer, cx| {
16001            let snapshot = buffer.snapshot(cx);
16002            let mut excerpt_ids = selections
16003                .iter()
16004                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16005                .collect::<Vec<_>>();
16006            excerpt_ids.sort();
16007            excerpt_ids.dedup();
16008            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16009        })
16010    }
16011
16012    pub fn expand_excerpt(
16013        &mut self,
16014        excerpt: ExcerptId,
16015        direction: ExpandExcerptDirection,
16016        window: &mut Window,
16017        cx: &mut Context<Self>,
16018    ) {
16019        let current_scroll_position = self.scroll_position(cx);
16020        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16021        let mut should_scroll_up = false;
16022
16023        if direction == ExpandExcerptDirection::Down {
16024            let multi_buffer = self.buffer.read(cx);
16025            let snapshot = multi_buffer.snapshot(cx);
16026            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16027                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16028                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16029            {
16030                let buffer_snapshot = buffer.read(cx).snapshot();
16031                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16032                let last_row = buffer_snapshot.max_point().row;
16033                let lines_below = last_row.saturating_sub(excerpt_end_row);
16034                should_scroll_up = lines_below >= lines_to_expand;
16035            }
16036        }
16037
16038        self.buffer.update(cx, |buffer, cx| {
16039            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16040        });
16041
16042        if should_scroll_up {
16043            let new_scroll_position =
16044                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
16045            self.set_scroll_position(new_scroll_position, window, cx);
16046        }
16047    }
16048
16049    pub fn go_to_singleton_buffer_point(
16050        &mut self,
16051        point: Point,
16052        window: &mut Window,
16053        cx: &mut Context<Self>,
16054    ) {
16055        self.go_to_singleton_buffer_range(point..point, window, cx);
16056    }
16057
16058    pub fn go_to_singleton_buffer_range(
16059        &mut self,
16060        range: Range<Point>,
16061        window: &mut Window,
16062        cx: &mut Context<Self>,
16063    ) {
16064        let multibuffer = self.buffer().read(cx);
16065        let Some(buffer) = multibuffer.as_singleton() else {
16066            return;
16067        };
16068        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16069            return;
16070        };
16071        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16072            return;
16073        };
16074        self.change_selections(
16075            SelectionEffects::default().nav_history(true),
16076            window,
16077            cx,
16078            |s| s.select_anchor_ranges([start..end]),
16079        );
16080    }
16081
16082    pub fn go_to_diagnostic(
16083        &mut self,
16084        action: &GoToDiagnostic,
16085        window: &mut Window,
16086        cx: &mut Context<Self>,
16087    ) {
16088        if !self.diagnostics_enabled() {
16089            return;
16090        }
16091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16092        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16093    }
16094
16095    pub fn go_to_prev_diagnostic(
16096        &mut self,
16097        action: &GoToPreviousDiagnostic,
16098        window: &mut Window,
16099        cx: &mut Context<Self>,
16100    ) {
16101        if !self.diagnostics_enabled() {
16102            return;
16103        }
16104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16105        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16106    }
16107
16108    pub fn go_to_diagnostic_impl(
16109        &mut self,
16110        direction: Direction,
16111        severity: GoToDiagnosticSeverityFilter,
16112        window: &mut Window,
16113        cx: &mut Context<Self>,
16114    ) {
16115        let buffer = self.buffer.read(cx).snapshot(cx);
16116        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16117
16118        let mut active_group_id = None;
16119        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16120            && active_group.active_range.start.to_offset(&buffer) == selection.start
16121        {
16122            active_group_id = Some(active_group.group_id);
16123        }
16124
16125        fn filtered<'a>(
16126            snapshot: EditorSnapshot,
16127            severity: GoToDiagnosticSeverityFilter,
16128            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16129        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16130            diagnostics
16131                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16132                .filter(|entry| entry.range.start != entry.range.end)
16133                .filter(|entry| !entry.diagnostic.is_unnecessary)
16134                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16135        }
16136
16137        let snapshot = self.snapshot(window, cx);
16138        let before = filtered(
16139            snapshot.clone(),
16140            severity,
16141            buffer
16142                .diagnostics_in_range(0..selection.start)
16143                .filter(|entry| entry.range.start <= selection.start),
16144        );
16145        let after = filtered(
16146            snapshot,
16147            severity,
16148            buffer
16149                .diagnostics_in_range(selection.start..buffer.len())
16150                .filter(|entry| entry.range.start >= selection.start),
16151        );
16152
16153        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16154        if direction == Direction::Prev {
16155            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16156            {
16157                for diagnostic in prev_diagnostics.into_iter().rev() {
16158                    if diagnostic.range.start != selection.start
16159                        || active_group_id
16160                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16161                    {
16162                        found = Some(diagnostic);
16163                        break 'outer;
16164                    }
16165                }
16166            }
16167        } else {
16168            for diagnostic in after.chain(before) {
16169                if diagnostic.range.start != selection.start
16170                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16171                {
16172                    found = Some(diagnostic);
16173                    break;
16174                }
16175            }
16176        }
16177        let Some(next_diagnostic) = found else {
16178            return;
16179        };
16180
16181        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16182        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16183            return;
16184        };
16185        self.change_selections(Default::default(), window, cx, |s| {
16186            s.select_ranges(vec![
16187                next_diagnostic.range.start..next_diagnostic.range.start,
16188            ])
16189        });
16190        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16191        self.refresh_edit_prediction(false, true, window, cx);
16192    }
16193
16194    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16195        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16196        let snapshot = self.snapshot(window, cx);
16197        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16198        self.go_to_hunk_before_or_after_position(
16199            &snapshot,
16200            selection.head(),
16201            Direction::Next,
16202            window,
16203            cx,
16204        );
16205    }
16206
16207    pub fn go_to_hunk_before_or_after_position(
16208        &mut self,
16209        snapshot: &EditorSnapshot,
16210        position: Point,
16211        direction: Direction,
16212        window: &mut Window,
16213        cx: &mut Context<Editor>,
16214    ) {
16215        let row = if direction == Direction::Next {
16216            self.hunk_after_position(snapshot, position)
16217                .map(|hunk| hunk.row_range.start)
16218        } else {
16219            self.hunk_before_position(snapshot, position)
16220        };
16221
16222        if let Some(row) = row {
16223            let destination = Point::new(row.0, 0);
16224            let autoscroll = Autoscroll::center();
16225
16226            self.unfold_ranges(&[destination..destination], false, false, cx);
16227            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16228                s.select_ranges([destination..destination]);
16229            });
16230        }
16231    }
16232
16233    fn hunk_after_position(
16234        &mut self,
16235        snapshot: &EditorSnapshot,
16236        position: Point,
16237    ) -> Option<MultiBufferDiffHunk> {
16238        snapshot
16239            .buffer_snapshot()
16240            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16241            .find(|hunk| hunk.row_range.start.0 > position.row)
16242            .or_else(|| {
16243                snapshot
16244                    .buffer_snapshot()
16245                    .diff_hunks_in_range(Point::zero()..position)
16246                    .find(|hunk| hunk.row_range.end.0 < position.row)
16247            })
16248    }
16249
16250    fn go_to_prev_hunk(
16251        &mut self,
16252        _: &GoToPreviousHunk,
16253        window: &mut Window,
16254        cx: &mut Context<Self>,
16255    ) {
16256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16257        let snapshot = self.snapshot(window, cx);
16258        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16259        self.go_to_hunk_before_or_after_position(
16260            &snapshot,
16261            selection.head(),
16262            Direction::Prev,
16263            window,
16264            cx,
16265        );
16266    }
16267
16268    fn hunk_before_position(
16269        &mut self,
16270        snapshot: &EditorSnapshot,
16271        position: Point,
16272    ) -> Option<MultiBufferRow> {
16273        snapshot
16274            .buffer_snapshot()
16275            .diff_hunk_before(position)
16276            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16277    }
16278
16279    fn go_to_next_change(
16280        &mut self,
16281        _: &GoToNextChange,
16282        window: &mut Window,
16283        cx: &mut Context<Self>,
16284    ) {
16285        if let Some(selections) = self
16286            .change_list
16287            .next_change(1, Direction::Next)
16288            .map(|s| s.to_vec())
16289        {
16290            self.change_selections(Default::default(), window, cx, |s| {
16291                let map = s.display_map();
16292                s.select_display_ranges(selections.iter().map(|a| {
16293                    let point = a.to_display_point(&map);
16294                    point..point
16295                }))
16296            })
16297        }
16298    }
16299
16300    fn go_to_previous_change(
16301        &mut self,
16302        _: &GoToPreviousChange,
16303        window: &mut Window,
16304        cx: &mut Context<Self>,
16305    ) {
16306        if let Some(selections) = self
16307            .change_list
16308            .next_change(1, Direction::Prev)
16309            .map(|s| s.to_vec())
16310        {
16311            self.change_selections(Default::default(), window, cx, |s| {
16312                let map = s.display_map();
16313                s.select_display_ranges(selections.iter().map(|a| {
16314                    let point = a.to_display_point(&map);
16315                    point..point
16316                }))
16317            })
16318        }
16319    }
16320
16321    pub fn go_to_next_document_highlight(
16322        &mut self,
16323        _: &GoToNextDocumentHighlight,
16324        window: &mut Window,
16325        cx: &mut Context<Self>,
16326    ) {
16327        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16328    }
16329
16330    pub fn go_to_prev_document_highlight(
16331        &mut self,
16332        _: &GoToPreviousDocumentHighlight,
16333        window: &mut Window,
16334        cx: &mut Context<Self>,
16335    ) {
16336        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16337    }
16338
16339    pub fn go_to_document_highlight_before_or_after_position(
16340        &mut self,
16341        direction: Direction,
16342        window: &mut Window,
16343        cx: &mut Context<Editor>,
16344    ) {
16345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16346        let snapshot = self.snapshot(window, cx);
16347        let buffer = &snapshot.buffer_snapshot();
16348        let position = self
16349            .selections
16350            .newest::<Point>(&snapshot.display_snapshot)
16351            .head();
16352        let anchor_position = buffer.anchor_after(position);
16353
16354        // Get all document highlights (both read and write)
16355        let mut all_highlights = Vec::new();
16356
16357        if let Some((_, read_highlights)) = self
16358            .background_highlights
16359            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16360        {
16361            all_highlights.extend(read_highlights.iter());
16362        }
16363
16364        if let Some((_, write_highlights)) = self
16365            .background_highlights
16366            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16367        {
16368            all_highlights.extend(write_highlights.iter());
16369        }
16370
16371        if all_highlights.is_empty() {
16372            return;
16373        }
16374
16375        // Sort highlights by position
16376        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16377
16378        let target_highlight = match direction {
16379            Direction::Next => {
16380                // Find the first highlight after the current position
16381                all_highlights
16382                    .iter()
16383                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16384            }
16385            Direction::Prev => {
16386                // Find the last highlight before the current position
16387                all_highlights
16388                    .iter()
16389                    .rev()
16390                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16391            }
16392        };
16393
16394        if let Some(highlight) = target_highlight {
16395            let destination = highlight.start.to_point(buffer);
16396            let autoscroll = Autoscroll::center();
16397
16398            self.unfold_ranges(&[destination..destination], false, false, cx);
16399            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16400                s.select_ranges([destination..destination]);
16401            });
16402        }
16403    }
16404
16405    fn go_to_line<T: 'static>(
16406        &mut self,
16407        position: Anchor,
16408        highlight_color: Option<Hsla>,
16409        window: &mut Window,
16410        cx: &mut Context<Self>,
16411    ) {
16412        let snapshot = self.snapshot(window, cx).display_snapshot;
16413        let position = position.to_point(&snapshot.buffer_snapshot());
16414        let start = snapshot
16415            .buffer_snapshot()
16416            .clip_point(Point::new(position.row, 0), Bias::Left);
16417        let end = start + Point::new(1, 0);
16418        let start = snapshot.buffer_snapshot().anchor_before(start);
16419        let end = snapshot.buffer_snapshot().anchor_before(end);
16420
16421        self.highlight_rows::<T>(
16422            start..end,
16423            highlight_color
16424                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16425            Default::default(),
16426            cx,
16427        );
16428
16429        if self.buffer.read(cx).is_singleton() {
16430            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16431        }
16432    }
16433
16434    pub fn go_to_definition(
16435        &mut self,
16436        _: &GoToDefinition,
16437        window: &mut Window,
16438        cx: &mut Context<Self>,
16439    ) -> Task<Result<Navigated>> {
16440        let definition =
16441            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16442        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16443        cx.spawn_in(window, async move |editor, cx| {
16444            if definition.await? == Navigated::Yes {
16445                return Ok(Navigated::Yes);
16446            }
16447            match fallback_strategy {
16448                GoToDefinitionFallback::None => Ok(Navigated::No),
16449                GoToDefinitionFallback::FindAllReferences => {
16450                    match editor.update_in(cx, |editor, window, cx| {
16451                        editor.find_all_references(&FindAllReferences, window, cx)
16452                    })? {
16453                        Some(references) => references.await,
16454                        None => Ok(Navigated::No),
16455                    }
16456                }
16457            }
16458        })
16459    }
16460
16461    pub fn go_to_declaration(
16462        &mut self,
16463        _: &GoToDeclaration,
16464        window: &mut Window,
16465        cx: &mut Context<Self>,
16466    ) -> Task<Result<Navigated>> {
16467        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16468    }
16469
16470    pub fn go_to_declaration_split(
16471        &mut self,
16472        _: &GoToDeclaration,
16473        window: &mut Window,
16474        cx: &mut Context<Self>,
16475    ) -> Task<Result<Navigated>> {
16476        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16477    }
16478
16479    pub fn go_to_implementation(
16480        &mut self,
16481        _: &GoToImplementation,
16482        window: &mut Window,
16483        cx: &mut Context<Self>,
16484    ) -> Task<Result<Navigated>> {
16485        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16486    }
16487
16488    pub fn go_to_implementation_split(
16489        &mut self,
16490        _: &GoToImplementationSplit,
16491        window: &mut Window,
16492        cx: &mut Context<Self>,
16493    ) -> Task<Result<Navigated>> {
16494        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16495    }
16496
16497    pub fn go_to_type_definition(
16498        &mut self,
16499        _: &GoToTypeDefinition,
16500        window: &mut Window,
16501        cx: &mut Context<Self>,
16502    ) -> Task<Result<Navigated>> {
16503        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16504    }
16505
16506    pub fn go_to_definition_split(
16507        &mut self,
16508        _: &GoToDefinitionSplit,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) -> Task<Result<Navigated>> {
16512        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16513    }
16514
16515    pub fn go_to_type_definition_split(
16516        &mut self,
16517        _: &GoToTypeDefinitionSplit,
16518        window: &mut Window,
16519        cx: &mut Context<Self>,
16520    ) -> Task<Result<Navigated>> {
16521        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16522    }
16523
16524    fn go_to_definition_of_kind(
16525        &mut self,
16526        kind: GotoDefinitionKind,
16527        split: bool,
16528        window: &mut Window,
16529        cx: &mut Context<Self>,
16530    ) -> Task<Result<Navigated>> {
16531        let Some(provider) = self.semantics_provider.clone() else {
16532            return Task::ready(Ok(Navigated::No));
16533        };
16534        let head = self
16535            .selections
16536            .newest::<usize>(&self.display_snapshot(cx))
16537            .head();
16538        let buffer = self.buffer.read(cx);
16539        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16540            return Task::ready(Ok(Navigated::No));
16541        };
16542        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16543            return Task::ready(Ok(Navigated::No));
16544        };
16545
16546        cx.spawn_in(window, async move |editor, cx| {
16547            let Some(definitions) = definitions.await? else {
16548                return Ok(Navigated::No);
16549            };
16550            let navigated = editor
16551                .update_in(cx, |editor, window, cx| {
16552                    editor.navigate_to_hover_links(
16553                        Some(kind),
16554                        definitions
16555                            .into_iter()
16556                            .filter(|location| {
16557                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16558                            })
16559                            .map(HoverLink::Text)
16560                            .collect::<Vec<_>>(),
16561                        split,
16562                        window,
16563                        cx,
16564                    )
16565                })?
16566                .await?;
16567            anyhow::Ok(navigated)
16568        })
16569    }
16570
16571    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16572        let selection = self.selections.newest_anchor();
16573        let head = selection.head();
16574        let tail = selection.tail();
16575
16576        let Some((buffer, start_position)) =
16577            self.buffer.read(cx).text_anchor_for_position(head, cx)
16578        else {
16579            return;
16580        };
16581
16582        let end_position = if head != tail {
16583            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16584                return;
16585            };
16586            Some(pos)
16587        } else {
16588            None
16589        };
16590
16591        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16592            let url = if let Some(end_pos) = end_position {
16593                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16594            } else {
16595                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16596            };
16597
16598            if let Some(url) = url {
16599                cx.update(|window, cx| {
16600                    if parse_zed_link(&url, cx).is_some() {
16601                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16602                    } else {
16603                        cx.open_url(&url);
16604                    }
16605                })?;
16606            }
16607
16608            anyhow::Ok(())
16609        });
16610
16611        url_finder.detach();
16612    }
16613
16614    pub fn open_selected_filename(
16615        &mut self,
16616        _: &OpenSelectedFilename,
16617        window: &mut Window,
16618        cx: &mut Context<Self>,
16619    ) {
16620        let Some(workspace) = self.workspace() else {
16621            return;
16622        };
16623
16624        let position = self.selections.newest_anchor().head();
16625
16626        let Some((buffer, buffer_position)) =
16627            self.buffer.read(cx).text_anchor_for_position(position, cx)
16628        else {
16629            return;
16630        };
16631
16632        let project = self.project.clone();
16633
16634        cx.spawn_in(window, async move |_, cx| {
16635            let result = find_file(&buffer, project, buffer_position, cx).await;
16636
16637            if let Some((_, path)) = result {
16638                workspace
16639                    .update_in(cx, |workspace, window, cx| {
16640                        workspace.open_resolved_path(path, window, cx)
16641                    })?
16642                    .await?;
16643            }
16644            anyhow::Ok(())
16645        })
16646        .detach();
16647    }
16648
16649    pub(crate) fn navigate_to_hover_links(
16650        &mut self,
16651        kind: Option<GotoDefinitionKind>,
16652        definitions: Vec<HoverLink>,
16653        split: bool,
16654        window: &mut Window,
16655        cx: &mut Context<Editor>,
16656    ) -> Task<Result<Navigated>> {
16657        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16658        let mut first_url_or_file = None;
16659        let definitions: Vec<_> = definitions
16660            .into_iter()
16661            .filter_map(|def| match def {
16662                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16663                HoverLink::InlayHint(lsp_location, server_id) => {
16664                    let computation =
16665                        self.compute_target_location(lsp_location, server_id, window, cx);
16666                    Some(cx.background_spawn(computation))
16667                }
16668                HoverLink::Url(url) => {
16669                    first_url_or_file = Some(Either::Left(url));
16670                    None
16671                }
16672                HoverLink::File(path) => {
16673                    first_url_or_file = Some(Either::Right(path));
16674                    None
16675                }
16676            })
16677            .collect();
16678
16679        let workspace = self.workspace();
16680
16681        cx.spawn_in(window, async move |editor, cx| {
16682            let locations: Vec<Location> = future::join_all(definitions)
16683                .await
16684                .into_iter()
16685                .filter_map(|location| location.transpose())
16686                .collect::<Result<_>>()
16687                .context("location tasks")?;
16688            let mut locations = cx.update(|_, cx| {
16689                locations
16690                    .into_iter()
16691                    .map(|location| {
16692                        let buffer = location.buffer.read(cx);
16693                        (location.buffer, location.range.to_point(buffer))
16694                    })
16695                    .into_group_map()
16696            })?;
16697            let mut num_locations = 0;
16698            for ranges in locations.values_mut() {
16699                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16700                ranges.dedup();
16701                num_locations += ranges.len();
16702            }
16703
16704            if num_locations > 1 {
16705                let Some(workspace) = workspace else {
16706                    return Ok(Navigated::No);
16707                };
16708
16709                let tab_kind = match kind {
16710                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16711                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16712                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16713                    Some(GotoDefinitionKind::Type) => "Types",
16714                };
16715                let title = editor
16716                    .update_in(cx, |_, _, cx| {
16717                        let target = locations
16718                            .iter()
16719                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16720                            .map(|(buffer, location)| {
16721                                buffer
16722                                    .read(cx)
16723                                    .text_for_range(location.clone())
16724                                    .collect::<String>()
16725                            })
16726                            .filter(|text| !text.contains('\n'))
16727                            .unique()
16728                            .take(3)
16729                            .join(", ");
16730                        if target.is_empty() {
16731                            tab_kind.to_owned()
16732                        } else {
16733                            format!("{tab_kind} for {target}")
16734                        }
16735                    })
16736                    .context("buffer title")?;
16737
16738                let opened = workspace
16739                    .update_in(cx, |workspace, window, cx| {
16740                        Self::open_locations_in_multibuffer(
16741                            workspace,
16742                            locations,
16743                            title,
16744                            split,
16745                            MultibufferSelectionMode::First,
16746                            window,
16747                            cx,
16748                        )
16749                    })
16750                    .is_ok();
16751
16752                anyhow::Ok(Navigated::from_bool(opened))
16753            } else if num_locations == 0 {
16754                // If there is one url or file, open it directly
16755                match first_url_or_file {
16756                    Some(Either::Left(url)) => {
16757                        cx.update(|_, cx| cx.open_url(&url))?;
16758                        Ok(Navigated::Yes)
16759                    }
16760                    Some(Either::Right(path)) => {
16761                        let Some(workspace) = workspace else {
16762                            return Ok(Navigated::No);
16763                        };
16764
16765                        workspace
16766                            .update_in(cx, |workspace, window, cx| {
16767                                workspace.open_resolved_path(path, window, cx)
16768                            })?
16769                            .await?;
16770                        Ok(Navigated::Yes)
16771                    }
16772                    None => Ok(Navigated::No),
16773                }
16774            } else {
16775                let Some(workspace) = workspace else {
16776                    return Ok(Navigated::No);
16777                };
16778
16779                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16780                let target_range = target_ranges.first().unwrap().clone();
16781
16782                editor.update_in(cx, |editor, window, cx| {
16783                    let range = target_range.to_point(target_buffer.read(cx));
16784                    let range = editor.range_for_match(&range);
16785                    let range = collapse_multiline_range(range);
16786
16787                    if !split
16788                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16789                    {
16790                        editor.go_to_singleton_buffer_range(range, window, cx);
16791                    } else {
16792                        let pane = workspace.read(cx).active_pane().clone();
16793                        window.defer(cx, move |window, cx| {
16794                            let target_editor: Entity<Self> =
16795                                workspace.update(cx, |workspace, cx| {
16796                                    let pane = if split {
16797                                        workspace.adjacent_pane(window, cx)
16798                                    } else {
16799                                        workspace.active_pane().clone()
16800                                    };
16801
16802                                    workspace.open_project_item(
16803                                        pane,
16804                                        target_buffer.clone(),
16805                                        true,
16806                                        true,
16807                                        window,
16808                                        cx,
16809                                    )
16810                                });
16811                            target_editor.update(cx, |target_editor, cx| {
16812                                // When selecting a definition in a different buffer, disable the nav history
16813                                // to avoid creating a history entry at the previous cursor location.
16814                                pane.update(cx, |pane, _| pane.disable_history());
16815                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16816                                pane.update(cx, |pane, _| pane.enable_history());
16817                            });
16818                        });
16819                    }
16820                    Navigated::Yes
16821                })
16822            }
16823        })
16824    }
16825
16826    fn compute_target_location(
16827        &self,
16828        lsp_location: lsp::Location,
16829        server_id: LanguageServerId,
16830        window: &mut Window,
16831        cx: &mut Context<Self>,
16832    ) -> Task<anyhow::Result<Option<Location>>> {
16833        let Some(project) = self.project.clone() else {
16834            return Task::ready(Ok(None));
16835        };
16836
16837        cx.spawn_in(window, async move |editor, cx| {
16838            let location_task = editor.update(cx, |_, cx| {
16839                project.update(cx, |project, cx| {
16840                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16841                })
16842            })?;
16843            let location = Some({
16844                let target_buffer_handle = location_task.await.context("open local buffer")?;
16845                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16846                    let target_start = target_buffer
16847                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16848                    let target_end = target_buffer
16849                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16850                    target_buffer.anchor_after(target_start)
16851                        ..target_buffer.anchor_before(target_end)
16852                })?;
16853                Location {
16854                    buffer: target_buffer_handle,
16855                    range,
16856                }
16857            });
16858            Ok(location)
16859        })
16860    }
16861
16862    pub fn find_all_references(
16863        &mut self,
16864        _: &FindAllReferences,
16865        window: &mut Window,
16866        cx: &mut Context<Self>,
16867    ) -> Option<Task<Result<Navigated>>> {
16868        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16869        let multi_buffer = self.buffer.read(cx);
16870        let head = selection.head();
16871
16872        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16873        let head_anchor = multi_buffer_snapshot.anchor_at(
16874            head,
16875            if head < selection.tail() {
16876                Bias::Right
16877            } else {
16878                Bias::Left
16879            },
16880        );
16881
16882        match self
16883            .find_all_references_task_sources
16884            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16885        {
16886            Ok(_) => {
16887                log::info!(
16888                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16889                );
16890                return None;
16891            }
16892            Err(i) => {
16893                self.find_all_references_task_sources.insert(i, head_anchor);
16894            }
16895        }
16896
16897        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16898        let workspace = self.workspace()?;
16899        let project = workspace.read(cx).project().clone();
16900        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16901        Some(cx.spawn_in(window, async move |editor, cx| {
16902            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16903                if let Ok(i) = editor
16904                    .find_all_references_task_sources
16905                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16906                {
16907                    editor.find_all_references_task_sources.remove(i);
16908                }
16909            });
16910
16911            let Some(locations) = references.await? else {
16912                return anyhow::Ok(Navigated::No);
16913            };
16914            let mut locations = cx.update(|_, cx| {
16915                locations
16916                    .into_iter()
16917                    .map(|location| {
16918                        let buffer = location.buffer.read(cx);
16919                        (location.buffer, location.range.to_point(buffer))
16920                    })
16921                    .into_group_map()
16922            })?;
16923            if locations.is_empty() {
16924                return anyhow::Ok(Navigated::No);
16925            }
16926            for ranges in locations.values_mut() {
16927                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16928                ranges.dedup();
16929            }
16930
16931            workspace.update_in(cx, |workspace, window, cx| {
16932                let target = locations
16933                    .iter()
16934                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16935                    .map(|(buffer, location)| {
16936                        buffer
16937                            .read(cx)
16938                            .text_for_range(location.clone())
16939                            .collect::<String>()
16940                    })
16941                    .filter(|text| !text.contains('\n'))
16942                    .unique()
16943                    .take(3)
16944                    .join(", ");
16945                let title = if target.is_empty() {
16946                    "References".to_owned()
16947                } else {
16948                    format!("References to {target}")
16949                };
16950                Self::open_locations_in_multibuffer(
16951                    workspace,
16952                    locations,
16953                    title,
16954                    false,
16955                    MultibufferSelectionMode::First,
16956                    window,
16957                    cx,
16958                );
16959                Navigated::Yes
16960            })
16961        }))
16962    }
16963
16964    /// Opens a multibuffer with the given project locations in it
16965    pub fn open_locations_in_multibuffer(
16966        workspace: &mut Workspace,
16967        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16968        title: String,
16969        split: bool,
16970        multibuffer_selection_mode: MultibufferSelectionMode,
16971        window: &mut Window,
16972        cx: &mut Context<Workspace>,
16973    ) {
16974        if locations.is_empty() {
16975            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16976            return;
16977        }
16978
16979        let capability = workspace.project().read(cx).capability();
16980        let mut ranges = <Vec<Range<Anchor>>>::new();
16981
16982        // a key to find existing multibuffer editors with the same set of locations
16983        // to prevent us from opening more and more multibuffer tabs for searches and the like
16984        let mut key = (title.clone(), vec![]);
16985        let excerpt_buffer = cx.new(|cx| {
16986            let key = &mut key.1;
16987            let mut multibuffer = MultiBuffer::new(capability);
16988            for (buffer, mut ranges_for_buffer) in locations {
16989                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16990                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16991                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16992                    PathKey::for_buffer(&buffer, cx),
16993                    buffer.clone(),
16994                    ranges_for_buffer,
16995                    multibuffer_context_lines(cx),
16996                    cx,
16997                );
16998                ranges.extend(new_ranges)
16999            }
17000
17001            multibuffer.with_title(title)
17002        });
17003        let existing = workspace.active_pane().update(cx, |pane, cx| {
17004            pane.items()
17005                .filter_map(|item| item.downcast::<Editor>())
17006                .find(|editor| {
17007                    editor
17008                        .read(cx)
17009                        .lookup_key
17010                        .as_ref()
17011                        .and_then(|it| {
17012                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17013                        })
17014                        .is_some_and(|it| *it == key)
17015                })
17016        });
17017        let editor = existing.unwrap_or_else(|| {
17018            cx.new(|cx| {
17019                let mut editor = Editor::for_multibuffer(
17020                    excerpt_buffer,
17021                    Some(workspace.project().clone()),
17022                    window,
17023                    cx,
17024                );
17025                editor.lookup_key = Some(Box::new(key));
17026                editor
17027            })
17028        });
17029        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17030            MultibufferSelectionMode::First => {
17031                if let Some(first_range) = ranges.first() {
17032                    editor.change_selections(
17033                        SelectionEffects::no_scroll(),
17034                        window,
17035                        cx,
17036                        |selections| {
17037                            selections.clear_disjoint();
17038                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17039                        },
17040                    );
17041                }
17042                editor.highlight_background::<Self>(
17043                    &ranges,
17044                    |theme| theme.colors().editor_highlighted_line_background,
17045                    cx,
17046                );
17047            }
17048            MultibufferSelectionMode::All => {
17049                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17050                    selections.clear_disjoint();
17051                    selections.select_anchor_ranges(ranges);
17052                });
17053            }
17054        });
17055
17056        let item = Box::new(editor);
17057        let item_id = item.item_id();
17058
17059        if split {
17060            let pane = workspace.adjacent_pane(window, cx);
17061            workspace.add_item(pane, item, None, true, true, window, cx);
17062        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17063            let (preview_item_id, preview_item_idx) =
17064                workspace.active_pane().read_with(cx, |pane, _| {
17065                    (pane.preview_item_id(), pane.preview_item_idx())
17066                });
17067
17068            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17069
17070            if let Some(preview_item_id) = preview_item_id {
17071                workspace.active_pane().update(cx, |pane, cx| {
17072                    pane.remove_item(preview_item_id, false, false, window, cx);
17073                });
17074            }
17075        } else {
17076            workspace.add_item_to_active_pane(item, None, true, window, cx);
17077        }
17078        workspace.active_pane().update(cx, |pane, cx| {
17079            pane.set_preview_item_id(Some(item_id), cx);
17080        });
17081    }
17082
17083    pub fn rename(
17084        &mut self,
17085        _: &Rename,
17086        window: &mut Window,
17087        cx: &mut Context<Self>,
17088    ) -> Option<Task<Result<()>>> {
17089        use language::ToOffset as _;
17090
17091        let provider = self.semantics_provider.clone()?;
17092        let selection = self.selections.newest_anchor().clone();
17093        let (cursor_buffer, cursor_buffer_position) = self
17094            .buffer
17095            .read(cx)
17096            .text_anchor_for_position(selection.head(), cx)?;
17097        let (tail_buffer, cursor_buffer_position_end) = self
17098            .buffer
17099            .read(cx)
17100            .text_anchor_for_position(selection.tail(), cx)?;
17101        if tail_buffer != cursor_buffer {
17102            return None;
17103        }
17104
17105        let snapshot = cursor_buffer.read(cx).snapshot();
17106        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17107        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17108        let prepare_rename = provider
17109            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17110            .unwrap_or_else(|| Task::ready(Ok(None)));
17111        drop(snapshot);
17112
17113        Some(cx.spawn_in(window, async move |this, cx| {
17114            let rename_range = if let Some(range) = prepare_rename.await? {
17115                Some(range)
17116            } else {
17117                this.update(cx, |this, cx| {
17118                    let buffer = this.buffer.read(cx).snapshot(cx);
17119                    let mut buffer_highlights = this
17120                        .document_highlights_for_position(selection.head(), &buffer)
17121                        .filter(|highlight| {
17122                            highlight.start.excerpt_id == selection.head().excerpt_id
17123                                && highlight.end.excerpt_id == selection.head().excerpt_id
17124                        });
17125                    buffer_highlights
17126                        .next()
17127                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17128                })?
17129            };
17130            if let Some(rename_range) = rename_range {
17131                this.update_in(cx, |this, window, cx| {
17132                    let snapshot = cursor_buffer.read(cx).snapshot();
17133                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17134                    let cursor_offset_in_rename_range =
17135                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17136                    let cursor_offset_in_rename_range_end =
17137                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17138
17139                    this.take_rename(false, window, cx);
17140                    let buffer = this.buffer.read(cx).read(cx);
17141                    let cursor_offset = selection.head().to_offset(&buffer);
17142                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17143                    let rename_end = rename_start + rename_buffer_range.len();
17144                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17145                    let mut old_highlight_id = None;
17146                    let old_name: Arc<str> = buffer
17147                        .chunks(rename_start..rename_end, true)
17148                        .map(|chunk| {
17149                            if old_highlight_id.is_none() {
17150                                old_highlight_id = chunk.syntax_highlight_id;
17151                            }
17152                            chunk.text
17153                        })
17154                        .collect::<String>()
17155                        .into();
17156
17157                    drop(buffer);
17158
17159                    // Position the selection in the rename editor so that it matches the current selection.
17160                    this.show_local_selections = false;
17161                    let rename_editor = cx.new(|cx| {
17162                        let mut editor = Editor::single_line(window, cx);
17163                        editor.buffer.update(cx, |buffer, cx| {
17164                            buffer.edit([(0..0, old_name.clone())], None, cx)
17165                        });
17166                        let rename_selection_range = match cursor_offset_in_rename_range
17167                            .cmp(&cursor_offset_in_rename_range_end)
17168                        {
17169                            Ordering::Equal => {
17170                                editor.select_all(&SelectAll, window, cx);
17171                                return editor;
17172                            }
17173                            Ordering::Less => {
17174                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17175                            }
17176                            Ordering::Greater => {
17177                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17178                            }
17179                        };
17180                        if rename_selection_range.end > old_name.len() {
17181                            editor.select_all(&SelectAll, window, cx);
17182                        } else {
17183                            editor.change_selections(Default::default(), window, cx, |s| {
17184                                s.select_ranges([rename_selection_range]);
17185                            });
17186                        }
17187                        editor
17188                    });
17189                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17190                        if e == &EditorEvent::Focused {
17191                            cx.emit(EditorEvent::FocusedIn)
17192                        }
17193                    })
17194                    .detach();
17195
17196                    let write_highlights =
17197                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17198                    let read_highlights =
17199                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17200                    let ranges = write_highlights
17201                        .iter()
17202                        .flat_map(|(_, ranges)| ranges.iter())
17203                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17204                        .cloned()
17205                        .collect();
17206
17207                    this.highlight_text::<Rename>(
17208                        ranges,
17209                        HighlightStyle {
17210                            fade_out: Some(0.6),
17211                            ..Default::default()
17212                        },
17213                        cx,
17214                    );
17215                    let rename_focus_handle = rename_editor.focus_handle(cx);
17216                    window.focus(&rename_focus_handle);
17217                    let block_id = this.insert_blocks(
17218                        [BlockProperties {
17219                            style: BlockStyle::Flex,
17220                            placement: BlockPlacement::Below(range.start),
17221                            height: Some(1),
17222                            render: Arc::new({
17223                                let rename_editor = rename_editor.clone();
17224                                move |cx: &mut BlockContext| {
17225                                    let mut text_style = cx.editor_style.text.clone();
17226                                    if let Some(highlight_style) = old_highlight_id
17227                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17228                                    {
17229                                        text_style = text_style.highlight(highlight_style);
17230                                    }
17231                                    div()
17232                                        .block_mouse_except_scroll()
17233                                        .pl(cx.anchor_x)
17234                                        .child(EditorElement::new(
17235                                            &rename_editor,
17236                                            EditorStyle {
17237                                                background: cx.theme().system().transparent,
17238                                                local_player: cx.editor_style.local_player,
17239                                                text: text_style,
17240                                                scrollbar_width: cx.editor_style.scrollbar_width,
17241                                                syntax: cx.editor_style.syntax.clone(),
17242                                                status: cx.editor_style.status.clone(),
17243                                                inlay_hints_style: HighlightStyle {
17244                                                    font_weight: Some(FontWeight::BOLD),
17245                                                    ..make_inlay_hints_style(cx.app)
17246                                                },
17247                                                edit_prediction_styles: make_suggestion_styles(
17248                                                    cx.app,
17249                                                ),
17250                                                ..EditorStyle::default()
17251                                            },
17252                                        ))
17253                                        .into_any_element()
17254                                }
17255                            }),
17256                            priority: 0,
17257                        }],
17258                        Some(Autoscroll::fit()),
17259                        cx,
17260                    )[0];
17261                    this.pending_rename = Some(RenameState {
17262                        range,
17263                        old_name,
17264                        editor: rename_editor,
17265                        block_id,
17266                    });
17267                })?;
17268            }
17269
17270            Ok(())
17271        }))
17272    }
17273
17274    pub fn confirm_rename(
17275        &mut self,
17276        _: &ConfirmRename,
17277        window: &mut Window,
17278        cx: &mut Context<Self>,
17279    ) -> Option<Task<Result<()>>> {
17280        let rename = self.take_rename(false, window, cx)?;
17281        let workspace = self.workspace()?.downgrade();
17282        let (buffer, start) = self
17283            .buffer
17284            .read(cx)
17285            .text_anchor_for_position(rename.range.start, cx)?;
17286        let (end_buffer, _) = self
17287            .buffer
17288            .read(cx)
17289            .text_anchor_for_position(rename.range.end, cx)?;
17290        if buffer != end_buffer {
17291            return None;
17292        }
17293
17294        let old_name = rename.old_name;
17295        let new_name = rename.editor.read(cx).text(cx);
17296
17297        let rename = self.semantics_provider.as_ref()?.perform_rename(
17298            &buffer,
17299            start,
17300            new_name.clone(),
17301            cx,
17302        )?;
17303
17304        Some(cx.spawn_in(window, async move |editor, cx| {
17305            let project_transaction = rename.await?;
17306            Self::open_project_transaction(
17307                &editor,
17308                workspace,
17309                project_transaction,
17310                format!("Rename: {}{}", old_name, new_name),
17311                cx,
17312            )
17313            .await?;
17314
17315            editor.update(cx, |editor, cx| {
17316                editor.refresh_document_highlights(cx);
17317            })?;
17318            Ok(())
17319        }))
17320    }
17321
17322    fn take_rename(
17323        &mut self,
17324        moving_cursor: bool,
17325        window: &mut Window,
17326        cx: &mut Context<Self>,
17327    ) -> Option<RenameState> {
17328        let rename = self.pending_rename.take()?;
17329        if rename.editor.focus_handle(cx).is_focused(window) {
17330            window.focus(&self.focus_handle);
17331        }
17332
17333        self.remove_blocks(
17334            [rename.block_id].into_iter().collect(),
17335            Some(Autoscroll::fit()),
17336            cx,
17337        );
17338        self.clear_highlights::<Rename>(cx);
17339        self.show_local_selections = true;
17340
17341        if moving_cursor {
17342            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17343                editor
17344                    .selections
17345                    .newest::<usize>(&editor.display_snapshot(cx))
17346                    .head()
17347            });
17348
17349            // Update the selection to match the position of the selection inside
17350            // the rename editor.
17351            let snapshot = self.buffer.read(cx).read(cx);
17352            let rename_range = rename.range.to_offset(&snapshot);
17353            let cursor_in_editor = snapshot
17354                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17355                .min(rename_range.end);
17356            drop(snapshot);
17357
17358            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17359                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17360            });
17361        } else {
17362            self.refresh_document_highlights(cx);
17363        }
17364
17365        Some(rename)
17366    }
17367
17368    pub fn pending_rename(&self) -> Option<&RenameState> {
17369        self.pending_rename.as_ref()
17370    }
17371
17372    fn format(
17373        &mut self,
17374        _: &Format,
17375        window: &mut Window,
17376        cx: &mut Context<Self>,
17377    ) -> Option<Task<Result<()>>> {
17378        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17379
17380        let project = match &self.project {
17381            Some(project) => project.clone(),
17382            None => return None,
17383        };
17384
17385        Some(self.perform_format(
17386            project,
17387            FormatTrigger::Manual,
17388            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17389            window,
17390            cx,
17391        ))
17392    }
17393
17394    fn format_selections(
17395        &mut self,
17396        _: &FormatSelections,
17397        window: &mut Window,
17398        cx: &mut Context<Self>,
17399    ) -> Option<Task<Result<()>>> {
17400        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17401
17402        let project = match &self.project {
17403            Some(project) => project.clone(),
17404            None => return None,
17405        };
17406
17407        let ranges = self
17408            .selections
17409            .all_adjusted(&self.display_snapshot(cx))
17410            .into_iter()
17411            .map(|selection| selection.range())
17412            .collect_vec();
17413
17414        Some(self.perform_format(
17415            project,
17416            FormatTrigger::Manual,
17417            FormatTarget::Ranges(ranges),
17418            window,
17419            cx,
17420        ))
17421    }
17422
17423    fn perform_format(
17424        &mut self,
17425        project: Entity<Project>,
17426        trigger: FormatTrigger,
17427        target: FormatTarget,
17428        window: &mut Window,
17429        cx: &mut Context<Self>,
17430    ) -> Task<Result<()>> {
17431        let buffer = self.buffer.clone();
17432        let (buffers, target) = match target {
17433            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17434            FormatTarget::Ranges(selection_ranges) => {
17435                let multi_buffer = buffer.read(cx);
17436                let snapshot = multi_buffer.read(cx);
17437                let mut buffers = HashSet::default();
17438                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17439                    BTreeMap::new();
17440                for selection_range in selection_ranges {
17441                    for (buffer, buffer_range, _) in
17442                        snapshot.range_to_buffer_ranges(selection_range)
17443                    {
17444                        let buffer_id = buffer.remote_id();
17445                        let start = buffer.anchor_before(buffer_range.start);
17446                        let end = buffer.anchor_after(buffer_range.end);
17447                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17448                        buffer_id_to_ranges
17449                            .entry(buffer_id)
17450                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17451                            .or_insert_with(|| vec![start..end]);
17452                    }
17453                }
17454                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17455            }
17456        };
17457
17458        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17459        let selections_prev = transaction_id_prev
17460            .and_then(|transaction_id_prev| {
17461                // default to selections as they were after the last edit, if we have them,
17462                // instead of how they are now.
17463                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17464                // will take you back to where you made the last edit, instead of staying where you scrolled
17465                self.selection_history
17466                    .transaction(transaction_id_prev)
17467                    .map(|t| t.0.clone())
17468            })
17469            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17470
17471        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17472        let format = project.update(cx, |project, cx| {
17473            project.format(buffers, target, true, trigger, cx)
17474        });
17475
17476        cx.spawn_in(window, async move |editor, cx| {
17477            let transaction = futures::select_biased! {
17478                transaction = format.log_err().fuse() => transaction,
17479                () = timeout => {
17480                    log::warn!("timed out waiting for formatting");
17481                    None
17482                }
17483            };
17484
17485            buffer
17486                .update(cx, |buffer, cx| {
17487                    if let Some(transaction) = transaction
17488                        && !buffer.is_singleton()
17489                    {
17490                        buffer.push_transaction(&transaction.0, cx);
17491                    }
17492                    cx.notify();
17493                })
17494                .ok();
17495
17496            if let Some(transaction_id_now) =
17497                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17498            {
17499                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17500                if has_new_transaction {
17501                    _ = editor.update(cx, |editor, _| {
17502                        editor
17503                            .selection_history
17504                            .insert_transaction(transaction_id_now, selections_prev);
17505                    });
17506                }
17507            }
17508
17509            Ok(())
17510        })
17511    }
17512
17513    fn organize_imports(
17514        &mut self,
17515        _: &OrganizeImports,
17516        window: &mut Window,
17517        cx: &mut Context<Self>,
17518    ) -> Option<Task<Result<()>>> {
17519        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17520        let project = match &self.project {
17521            Some(project) => project.clone(),
17522            None => return None,
17523        };
17524        Some(self.perform_code_action_kind(
17525            project,
17526            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17527            window,
17528            cx,
17529        ))
17530    }
17531
17532    fn perform_code_action_kind(
17533        &mut self,
17534        project: Entity<Project>,
17535        kind: CodeActionKind,
17536        window: &mut Window,
17537        cx: &mut Context<Self>,
17538    ) -> Task<Result<()>> {
17539        let buffer = self.buffer.clone();
17540        let buffers = buffer.read(cx).all_buffers();
17541        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17542        let apply_action = project.update(cx, |project, cx| {
17543            project.apply_code_action_kind(buffers, kind, true, cx)
17544        });
17545        cx.spawn_in(window, async move |_, cx| {
17546            let transaction = futures::select_biased! {
17547                () = timeout => {
17548                    log::warn!("timed out waiting for executing code action");
17549                    None
17550                }
17551                transaction = apply_action.log_err().fuse() => transaction,
17552            };
17553            buffer
17554                .update(cx, |buffer, cx| {
17555                    // check if we need this
17556                    if let Some(transaction) = transaction
17557                        && !buffer.is_singleton()
17558                    {
17559                        buffer.push_transaction(&transaction.0, cx);
17560                    }
17561                    cx.notify();
17562                })
17563                .ok();
17564            Ok(())
17565        })
17566    }
17567
17568    pub fn restart_language_server(
17569        &mut self,
17570        _: &RestartLanguageServer,
17571        _: &mut Window,
17572        cx: &mut Context<Self>,
17573    ) {
17574        if let Some(project) = self.project.clone() {
17575            self.buffer.update(cx, |multi_buffer, cx| {
17576                project.update(cx, |project, cx| {
17577                    project.restart_language_servers_for_buffers(
17578                        multi_buffer.all_buffers().into_iter().collect(),
17579                        HashSet::default(),
17580                        cx,
17581                    );
17582                });
17583            })
17584        }
17585    }
17586
17587    pub fn stop_language_server(
17588        &mut self,
17589        _: &StopLanguageServer,
17590        _: &mut Window,
17591        cx: &mut Context<Self>,
17592    ) {
17593        if let Some(project) = self.project.clone() {
17594            self.buffer.update(cx, |multi_buffer, cx| {
17595                project.update(cx, |project, cx| {
17596                    project.stop_language_servers_for_buffers(
17597                        multi_buffer.all_buffers().into_iter().collect(),
17598                        HashSet::default(),
17599                        cx,
17600                    );
17601                    cx.emit(project::Event::RefreshInlayHints);
17602                });
17603            });
17604        }
17605    }
17606
17607    fn cancel_language_server_work(
17608        workspace: &mut Workspace,
17609        _: &actions::CancelLanguageServerWork,
17610        _: &mut Window,
17611        cx: &mut Context<Workspace>,
17612    ) {
17613        let project = workspace.project();
17614        let buffers = workspace
17615            .active_item(cx)
17616            .and_then(|item| item.act_as::<Editor>(cx))
17617            .map_or(HashSet::default(), |editor| {
17618                editor.read(cx).buffer.read(cx).all_buffers()
17619            });
17620        project.update(cx, |project, cx| {
17621            project.cancel_language_server_work_for_buffers(buffers, cx);
17622        });
17623    }
17624
17625    fn show_character_palette(
17626        &mut self,
17627        _: &ShowCharacterPalette,
17628        window: &mut Window,
17629        _: &mut Context<Self>,
17630    ) {
17631        window.show_character_palette();
17632    }
17633
17634    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17635        if !self.diagnostics_enabled() {
17636            return;
17637        }
17638
17639        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17640            let buffer = self.buffer.read(cx).snapshot(cx);
17641            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17642            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17643            let is_valid = buffer
17644                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17645                .any(|entry| {
17646                    entry.diagnostic.is_primary
17647                        && !entry.range.is_empty()
17648                        && entry.range.start == primary_range_start
17649                        && entry.diagnostic.message == active_diagnostics.active_message
17650                });
17651
17652            if !is_valid {
17653                self.dismiss_diagnostics(cx);
17654            }
17655        }
17656    }
17657
17658    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17659        match &self.active_diagnostics {
17660            ActiveDiagnostic::Group(group) => Some(group),
17661            _ => None,
17662        }
17663    }
17664
17665    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17666        if !self.diagnostics_enabled() {
17667            return;
17668        }
17669        self.dismiss_diagnostics(cx);
17670        self.active_diagnostics = ActiveDiagnostic::All;
17671    }
17672
17673    fn activate_diagnostics(
17674        &mut self,
17675        buffer_id: BufferId,
17676        diagnostic: DiagnosticEntryRef<'_, usize>,
17677        window: &mut Window,
17678        cx: &mut Context<Self>,
17679    ) {
17680        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17681            return;
17682        }
17683        self.dismiss_diagnostics(cx);
17684        let snapshot = self.snapshot(window, cx);
17685        let buffer = self.buffer.read(cx).snapshot(cx);
17686        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17687            return;
17688        };
17689
17690        let diagnostic_group = buffer
17691            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17692            .collect::<Vec<_>>();
17693
17694        let blocks =
17695            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17696
17697        let blocks = self.display_map.update(cx, |display_map, cx| {
17698            display_map.insert_blocks(blocks, cx).into_iter().collect()
17699        });
17700        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17701            active_range: buffer.anchor_before(diagnostic.range.start)
17702                ..buffer.anchor_after(diagnostic.range.end),
17703            active_message: diagnostic.diagnostic.message.clone(),
17704            group_id: diagnostic.diagnostic.group_id,
17705            blocks,
17706        });
17707        cx.notify();
17708    }
17709
17710    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17711        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17712            return;
17713        };
17714
17715        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17716        if let ActiveDiagnostic::Group(group) = prev {
17717            self.display_map.update(cx, |display_map, cx| {
17718                display_map.remove_blocks(group.blocks, cx);
17719            });
17720            cx.notify();
17721        }
17722    }
17723
17724    /// Disable inline diagnostics rendering for this editor.
17725    pub fn disable_inline_diagnostics(&mut self) {
17726        self.inline_diagnostics_enabled = false;
17727        self.inline_diagnostics_update = Task::ready(());
17728        self.inline_diagnostics.clear();
17729    }
17730
17731    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17732        self.diagnostics_enabled = false;
17733        self.dismiss_diagnostics(cx);
17734        self.inline_diagnostics_update = Task::ready(());
17735        self.inline_diagnostics.clear();
17736    }
17737
17738    pub fn disable_word_completions(&mut self) {
17739        self.word_completions_enabled = false;
17740    }
17741
17742    pub fn diagnostics_enabled(&self) -> bool {
17743        self.diagnostics_enabled && self.mode.is_full()
17744    }
17745
17746    pub fn inline_diagnostics_enabled(&self) -> bool {
17747        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17748    }
17749
17750    pub fn show_inline_diagnostics(&self) -> bool {
17751        self.show_inline_diagnostics
17752    }
17753
17754    pub fn toggle_inline_diagnostics(
17755        &mut self,
17756        _: &ToggleInlineDiagnostics,
17757        window: &mut Window,
17758        cx: &mut Context<Editor>,
17759    ) {
17760        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17761        self.refresh_inline_diagnostics(false, window, cx);
17762    }
17763
17764    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17765        self.diagnostics_max_severity = severity;
17766        self.display_map.update(cx, |display_map, _| {
17767            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17768        });
17769    }
17770
17771    pub fn toggle_diagnostics(
17772        &mut self,
17773        _: &ToggleDiagnostics,
17774        window: &mut Window,
17775        cx: &mut Context<Editor>,
17776    ) {
17777        if !self.diagnostics_enabled() {
17778            return;
17779        }
17780
17781        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17782            EditorSettings::get_global(cx)
17783                .diagnostics_max_severity
17784                .filter(|severity| severity != &DiagnosticSeverity::Off)
17785                .unwrap_or(DiagnosticSeverity::Hint)
17786        } else {
17787            DiagnosticSeverity::Off
17788        };
17789        self.set_max_diagnostics_severity(new_severity, cx);
17790        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17791            self.active_diagnostics = ActiveDiagnostic::None;
17792            self.inline_diagnostics_update = Task::ready(());
17793            self.inline_diagnostics.clear();
17794        } else {
17795            self.refresh_inline_diagnostics(false, window, cx);
17796        }
17797
17798        cx.notify();
17799    }
17800
17801    pub fn toggle_minimap(
17802        &mut self,
17803        _: &ToggleMinimap,
17804        window: &mut Window,
17805        cx: &mut Context<Editor>,
17806    ) {
17807        if self.supports_minimap(cx) {
17808            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17809        }
17810    }
17811
17812    fn refresh_inline_diagnostics(
17813        &mut self,
17814        debounce: bool,
17815        window: &mut Window,
17816        cx: &mut Context<Self>,
17817    ) {
17818        let max_severity = ProjectSettings::get_global(cx)
17819            .diagnostics
17820            .inline
17821            .max_severity
17822            .unwrap_or(self.diagnostics_max_severity);
17823
17824        if !self.inline_diagnostics_enabled()
17825            || !self.show_inline_diagnostics
17826            || max_severity == DiagnosticSeverity::Off
17827        {
17828            self.inline_diagnostics_update = Task::ready(());
17829            self.inline_diagnostics.clear();
17830            return;
17831        }
17832
17833        let debounce_ms = ProjectSettings::get_global(cx)
17834            .diagnostics
17835            .inline
17836            .update_debounce_ms;
17837        let debounce = if debounce && debounce_ms > 0 {
17838            Some(Duration::from_millis(debounce_ms))
17839        } else {
17840            None
17841        };
17842        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17843            if let Some(debounce) = debounce {
17844                cx.background_executor().timer(debounce).await;
17845            }
17846            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17847                editor
17848                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17849                    .ok()
17850            }) else {
17851                return;
17852            };
17853
17854            let new_inline_diagnostics = cx
17855                .background_spawn(async move {
17856                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17857                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17858                        let message = diagnostic_entry
17859                            .diagnostic
17860                            .message
17861                            .split_once('\n')
17862                            .map(|(line, _)| line)
17863                            .map(SharedString::new)
17864                            .unwrap_or_else(|| {
17865                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17866                            });
17867                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17868                        let (Ok(i) | Err(i)) = inline_diagnostics
17869                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17870                        inline_diagnostics.insert(
17871                            i,
17872                            (
17873                                start_anchor,
17874                                InlineDiagnostic {
17875                                    message,
17876                                    group_id: diagnostic_entry.diagnostic.group_id,
17877                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17878                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17879                                    severity: diagnostic_entry.diagnostic.severity,
17880                                },
17881                            ),
17882                        );
17883                    }
17884                    inline_diagnostics
17885                })
17886                .await;
17887
17888            editor
17889                .update(cx, |editor, cx| {
17890                    editor.inline_diagnostics = new_inline_diagnostics;
17891                    cx.notify();
17892                })
17893                .ok();
17894        });
17895    }
17896
17897    fn pull_diagnostics(
17898        &mut self,
17899        buffer_id: Option<BufferId>,
17900        window: &Window,
17901        cx: &mut Context<Self>,
17902    ) -> Option<()> {
17903        if self.ignore_lsp_data() {
17904            return None;
17905        }
17906        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17907            .diagnostics
17908            .lsp_pull_diagnostics;
17909        if !pull_diagnostics_settings.enabled {
17910            return None;
17911        }
17912        let project = self.project()?.downgrade();
17913        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17914        let mut buffers = self.buffer.read(cx).all_buffers();
17915        buffers.retain(|buffer| {
17916            let buffer_id_to_retain = buffer.read(cx).remote_id();
17917            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17918                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17919        });
17920        if buffers.is_empty() {
17921            self.pull_diagnostics_task = Task::ready(());
17922            return None;
17923        }
17924
17925        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17926            cx.background_executor().timer(debounce).await;
17927
17928            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17929                buffers
17930                    .into_iter()
17931                    .filter_map(|buffer| {
17932                        project
17933                            .update(cx, |project, cx| {
17934                                project.lsp_store().update(cx, |lsp_store, cx| {
17935                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17936                                })
17937                            })
17938                            .ok()
17939                    })
17940                    .collect::<FuturesUnordered<_>>()
17941            }) else {
17942                return;
17943            };
17944
17945            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17946                match pull_task {
17947                    Ok(()) => {
17948                        if editor
17949                            .update_in(cx, |editor, window, cx| {
17950                                editor.update_diagnostics_state(window, cx);
17951                            })
17952                            .is_err()
17953                        {
17954                            return;
17955                        }
17956                    }
17957                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17958                }
17959            }
17960        });
17961
17962        Some(())
17963    }
17964
17965    pub fn set_selections_from_remote(
17966        &mut self,
17967        selections: Vec<Selection<Anchor>>,
17968        pending_selection: Option<Selection<Anchor>>,
17969        window: &mut Window,
17970        cx: &mut Context<Self>,
17971    ) {
17972        let old_cursor_position = self.selections.newest_anchor().head();
17973        self.selections.change_with(cx, |s| {
17974            s.select_anchors(selections);
17975            if let Some(pending_selection) = pending_selection {
17976                s.set_pending(pending_selection, SelectMode::Character);
17977            } else {
17978                s.clear_pending();
17979            }
17980        });
17981        self.selections_did_change(
17982            false,
17983            &old_cursor_position,
17984            SelectionEffects::default(),
17985            window,
17986            cx,
17987        );
17988    }
17989
17990    pub fn transact(
17991        &mut self,
17992        window: &mut Window,
17993        cx: &mut Context<Self>,
17994        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17995    ) -> Option<TransactionId> {
17996        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17997            this.start_transaction_at(Instant::now(), window, cx);
17998            update(this, window, cx);
17999            this.end_transaction_at(Instant::now(), cx)
18000        })
18001    }
18002
18003    pub fn start_transaction_at(
18004        &mut self,
18005        now: Instant,
18006        window: &mut Window,
18007        cx: &mut Context<Self>,
18008    ) -> Option<TransactionId> {
18009        self.end_selection(window, cx);
18010        if let Some(tx_id) = self
18011            .buffer
18012            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18013        {
18014            self.selection_history
18015                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18016            cx.emit(EditorEvent::TransactionBegun {
18017                transaction_id: tx_id,
18018            });
18019            Some(tx_id)
18020        } else {
18021            None
18022        }
18023    }
18024
18025    pub fn end_transaction_at(
18026        &mut self,
18027        now: Instant,
18028        cx: &mut Context<Self>,
18029    ) -> Option<TransactionId> {
18030        if let Some(transaction_id) = self
18031            .buffer
18032            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18033        {
18034            if let Some((_, end_selections)) =
18035                self.selection_history.transaction_mut(transaction_id)
18036            {
18037                *end_selections = Some(self.selections.disjoint_anchors_arc());
18038            } else {
18039                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18040            }
18041
18042            cx.emit(EditorEvent::Edited { transaction_id });
18043            Some(transaction_id)
18044        } else {
18045            None
18046        }
18047    }
18048
18049    pub fn modify_transaction_selection_history(
18050        &mut self,
18051        transaction_id: TransactionId,
18052        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18053    ) -> bool {
18054        self.selection_history
18055            .transaction_mut(transaction_id)
18056            .map(modify)
18057            .is_some()
18058    }
18059
18060    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18061        if self.selection_mark_mode {
18062            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18063                s.move_with(|_, sel| {
18064                    sel.collapse_to(sel.head(), SelectionGoal::None);
18065                });
18066            })
18067        }
18068        self.selection_mark_mode = true;
18069        cx.notify();
18070    }
18071
18072    pub fn swap_selection_ends(
18073        &mut self,
18074        _: &actions::SwapSelectionEnds,
18075        window: &mut Window,
18076        cx: &mut Context<Self>,
18077    ) {
18078        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18079            s.move_with(|_, sel| {
18080                if sel.start != sel.end {
18081                    sel.reversed = !sel.reversed
18082                }
18083            });
18084        });
18085        self.request_autoscroll(Autoscroll::newest(), cx);
18086        cx.notify();
18087    }
18088
18089    pub fn toggle_focus(
18090        workspace: &mut Workspace,
18091        _: &actions::ToggleFocus,
18092        window: &mut Window,
18093        cx: &mut Context<Workspace>,
18094    ) {
18095        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18096            return;
18097        };
18098        workspace.activate_item(&item, true, true, window, cx);
18099    }
18100
18101    pub fn toggle_fold(
18102        &mut self,
18103        _: &actions::ToggleFold,
18104        window: &mut Window,
18105        cx: &mut Context<Self>,
18106    ) {
18107        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18108            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18109            let selection = self.selections.newest::<Point>(&display_map);
18110
18111            let range = if selection.is_empty() {
18112                let point = selection.head().to_display_point(&display_map);
18113                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18114                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18115                    .to_point(&display_map);
18116                start..end
18117            } else {
18118                selection.range()
18119            };
18120            if display_map.folds_in_range(range).next().is_some() {
18121                self.unfold_lines(&Default::default(), window, cx)
18122            } else {
18123                self.fold(&Default::default(), window, cx)
18124            }
18125        } else {
18126            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18127            let buffer_ids: HashSet<_> = self
18128                .selections
18129                .disjoint_anchor_ranges()
18130                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18131                .collect();
18132
18133            let should_unfold = buffer_ids
18134                .iter()
18135                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18136
18137            for buffer_id in buffer_ids {
18138                if should_unfold {
18139                    self.unfold_buffer(buffer_id, cx);
18140                } else {
18141                    self.fold_buffer(buffer_id, cx);
18142                }
18143            }
18144        }
18145    }
18146
18147    pub fn toggle_fold_recursive(
18148        &mut self,
18149        _: &actions::ToggleFoldRecursive,
18150        window: &mut Window,
18151        cx: &mut Context<Self>,
18152    ) {
18153        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18154
18155        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18156        let range = if selection.is_empty() {
18157            let point = selection.head().to_display_point(&display_map);
18158            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18159            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18160                .to_point(&display_map);
18161            start..end
18162        } else {
18163            selection.range()
18164        };
18165        if display_map.folds_in_range(range).next().is_some() {
18166            self.unfold_recursive(&Default::default(), window, cx)
18167        } else {
18168            self.fold_recursive(&Default::default(), window, cx)
18169        }
18170    }
18171
18172    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18173        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18174            let mut to_fold = Vec::new();
18175            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18176            let selections = self.selections.all_adjusted(&display_map);
18177
18178            for selection in selections {
18179                let range = selection.range().sorted();
18180                let buffer_start_row = range.start.row;
18181
18182                if range.start.row != range.end.row {
18183                    let mut found = false;
18184                    let mut row = range.start.row;
18185                    while row <= range.end.row {
18186                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18187                        {
18188                            found = true;
18189                            row = crease.range().end.row + 1;
18190                            to_fold.push(crease);
18191                        } else {
18192                            row += 1
18193                        }
18194                    }
18195                    if found {
18196                        continue;
18197                    }
18198                }
18199
18200                for row in (0..=range.start.row).rev() {
18201                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18202                        && crease.range().end.row >= buffer_start_row
18203                    {
18204                        to_fold.push(crease);
18205                        if row <= range.start.row {
18206                            break;
18207                        }
18208                    }
18209                }
18210            }
18211
18212            self.fold_creases(to_fold, true, window, cx);
18213        } else {
18214            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18215            let buffer_ids = self
18216                .selections
18217                .disjoint_anchor_ranges()
18218                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18219                .collect::<HashSet<_>>();
18220            for buffer_id in buffer_ids {
18221                self.fold_buffer(buffer_id, cx);
18222            }
18223        }
18224    }
18225
18226    pub fn toggle_fold_all(
18227        &mut self,
18228        _: &actions::ToggleFoldAll,
18229        window: &mut Window,
18230        cx: &mut Context<Self>,
18231    ) {
18232        if self.buffer.read(cx).is_singleton() {
18233            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18234            let has_folds = display_map
18235                .folds_in_range(0..display_map.buffer_snapshot().len())
18236                .next()
18237                .is_some();
18238
18239            if has_folds {
18240                self.unfold_all(&actions::UnfoldAll, window, cx);
18241            } else {
18242                self.fold_all(&actions::FoldAll, window, cx);
18243            }
18244        } else {
18245            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18246            let should_unfold = buffer_ids
18247                .iter()
18248                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18249
18250            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18251                editor
18252                    .update_in(cx, |editor, _, cx| {
18253                        for buffer_id in buffer_ids {
18254                            if should_unfold {
18255                                editor.unfold_buffer(buffer_id, cx);
18256                            } else {
18257                                editor.fold_buffer(buffer_id, cx);
18258                            }
18259                        }
18260                    })
18261                    .ok();
18262            });
18263        }
18264    }
18265
18266    fn fold_at_level(
18267        &mut self,
18268        fold_at: &FoldAtLevel,
18269        window: &mut Window,
18270        cx: &mut Context<Self>,
18271    ) {
18272        if !self.buffer.read(cx).is_singleton() {
18273            return;
18274        }
18275
18276        let fold_at_level = fold_at.0;
18277        let snapshot = self.buffer.read(cx).snapshot(cx);
18278        let mut to_fold = Vec::new();
18279        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18280
18281        let row_ranges_to_keep: Vec<Range<u32>> = self
18282            .selections
18283            .all::<Point>(&self.display_snapshot(cx))
18284            .into_iter()
18285            .map(|sel| sel.start.row..sel.end.row)
18286            .collect();
18287
18288        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18289            while start_row < end_row {
18290                match self
18291                    .snapshot(window, cx)
18292                    .crease_for_buffer_row(MultiBufferRow(start_row))
18293                {
18294                    Some(crease) => {
18295                        let nested_start_row = crease.range().start.row + 1;
18296                        let nested_end_row = crease.range().end.row;
18297
18298                        if current_level < fold_at_level {
18299                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18300                        } else if current_level == fold_at_level {
18301                            // Fold iff there is no selection completely contained within the fold region
18302                            if !row_ranges_to_keep.iter().any(|selection| {
18303                                selection.end >= nested_start_row
18304                                    && selection.start <= nested_end_row
18305                            }) {
18306                                to_fold.push(crease);
18307                            }
18308                        }
18309
18310                        start_row = nested_end_row + 1;
18311                    }
18312                    None => start_row += 1,
18313                }
18314            }
18315        }
18316
18317        self.fold_creases(to_fold, true, window, cx);
18318    }
18319
18320    pub fn fold_at_level_1(
18321        &mut self,
18322        _: &actions::FoldAtLevel1,
18323        window: &mut Window,
18324        cx: &mut Context<Self>,
18325    ) {
18326        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18327    }
18328
18329    pub fn fold_at_level_2(
18330        &mut self,
18331        _: &actions::FoldAtLevel2,
18332        window: &mut Window,
18333        cx: &mut Context<Self>,
18334    ) {
18335        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18336    }
18337
18338    pub fn fold_at_level_3(
18339        &mut self,
18340        _: &actions::FoldAtLevel3,
18341        window: &mut Window,
18342        cx: &mut Context<Self>,
18343    ) {
18344        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18345    }
18346
18347    pub fn fold_at_level_4(
18348        &mut self,
18349        _: &actions::FoldAtLevel4,
18350        window: &mut Window,
18351        cx: &mut Context<Self>,
18352    ) {
18353        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18354    }
18355
18356    pub fn fold_at_level_5(
18357        &mut self,
18358        _: &actions::FoldAtLevel5,
18359        window: &mut Window,
18360        cx: &mut Context<Self>,
18361    ) {
18362        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18363    }
18364
18365    pub fn fold_at_level_6(
18366        &mut self,
18367        _: &actions::FoldAtLevel6,
18368        window: &mut Window,
18369        cx: &mut Context<Self>,
18370    ) {
18371        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18372    }
18373
18374    pub fn fold_at_level_7(
18375        &mut self,
18376        _: &actions::FoldAtLevel7,
18377        window: &mut Window,
18378        cx: &mut Context<Self>,
18379    ) {
18380        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18381    }
18382
18383    pub fn fold_at_level_8(
18384        &mut self,
18385        _: &actions::FoldAtLevel8,
18386        window: &mut Window,
18387        cx: &mut Context<Self>,
18388    ) {
18389        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18390    }
18391
18392    pub fn fold_at_level_9(
18393        &mut self,
18394        _: &actions::FoldAtLevel9,
18395        window: &mut Window,
18396        cx: &mut Context<Self>,
18397    ) {
18398        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18399    }
18400
18401    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18402        if self.buffer.read(cx).is_singleton() {
18403            let mut fold_ranges = Vec::new();
18404            let snapshot = self.buffer.read(cx).snapshot(cx);
18405
18406            for row in 0..snapshot.max_row().0 {
18407                if let Some(foldable_range) = self
18408                    .snapshot(window, cx)
18409                    .crease_for_buffer_row(MultiBufferRow(row))
18410                {
18411                    fold_ranges.push(foldable_range);
18412                }
18413            }
18414
18415            self.fold_creases(fold_ranges, true, window, cx);
18416        } else {
18417            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18418                editor
18419                    .update_in(cx, |editor, _, cx| {
18420                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18421                            editor.fold_buffer(buffer_id, cx);
18422                        }
18423                    })
18424                    .ok();
18425            });
18426        }
18427    }
18428
18429    pub fn fold_function_bodies(
18430        &mut self,
18431        _: &actions::FoldFunctionBodies,
18432        window: &mut Window,
18433        cx: &mut Context<Self>,
18434    ) {
18435        let snapshot = self.buffer.read(cx).snapshot(cx);
18436
18437        let ranges = snapshot
18438            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18439            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18440            .collect::<Vec<_>>();
18441
18442        let creases = ranges
18443            .into_iter()
18444            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18445            .collect();
18446
18447        self.fold_creases(creases, true, window, cx);
18448    }
18449
18450    pub fn fold_recursive(
18451        &mut self,
18452        _: &actions::FoldRecursive,
18453        window: &mut Window,
18454        cx: &mut Context<Self>,
18455    ) {
18456        let mut to_fold = Vec::new();
18457        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18458        let selections = self.selections.all_adjusted(&display_map);
18459
18460        for selection in selections {
18461            let range = selection.range().sorted();
18462            let buffer_start_row = range.start.row;
18463
18464            if range.start.row != range.end.row {
18465                let mut found = false;
18466                for row in range.start.row..=range.end.row {
18467                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18468                        found = true;
18469                        to_fold.push(crease);
18470                    }
18471                }
18472                if found {
18473                    continue;
18474                }
18475            }
18476
18477            for row in (0..=range.start.row).rev() {
18478                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18479                    if crease.range().end.row >= buffer_start_row {
18480                        to_fold.push(crease);
18481                    } else {
18482                        break;
18483                    }
18484                }
18485            }
18486        }
18487
18488        self.fold_creases(to_fold, true, window, cx);
18489    }
18490
18491    pub fn fold_at(
18492        &mut self,
18493        buffer_row: MultiBufferRow,
18494        window: &mut Window,
18495        cx: &mut Context<Self>,
18496    ) {
18497        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18498
18499        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18500            let autoscroll = self
18501                .selections
18502                .all::<Point>(&display_map)
18503                .iter()
18504                .any(|selection| crease.range().overlaps(&selection.range()));
18505
18506            self.fold_creases(vec![crease], autoscroll, window, cx);
18507        }
18508    }
18509
18510    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18511        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18512            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18513            let buffer = display_map.buffer_snapshot();
18514            let selections = self.selections.all::<Point>(&display_map);
18515            let ranges = selections
18516                .iter()
18517                .map(|s| {
18518                    let range = s.display_range(&display_map).sorted();
18519                    let mut start = range.start.to_point(&display_map);
18520                    let mut end = range.end.to_point(&display_map);
18521                    start.column = 0;
18522                    end.column = buffer.line_len(MultiBufferRow(end.row));
18523                    start..end
18524                })
18525                .collect::<Vec<_>>();
18526
18527            self.unfold_ranges(&ranges, true, true, cx);
18528        } else {
18529            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18530            let buffer_ids = self
18531                .selections
18532                .disjoint_anchor_ranges()
18533                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18534                .collect::<HashSet<_>>();
18535            for buffer_id in buffer_ids {
18536                self.unfold_buffer(buffer_id, cx);
18537            }
18538        }
18539    }
18540
18541    pub fn unfold_recursive(
18542        &mut self,
18543        _: &UnfoldRecursive,
18544        _window: &mut Window,
18545        cx: &mut Context<Self>,
18546    ) {
18547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18548        let selections = self.selections.all::<Point>(&display_map);
18549        let ranges = selections
18550            .iter()
18551            .map(|s| {
18552                let mut range = s.display_range(&display_map).sorted();
18553                *range.start.column_mut() = 0;
18554                *range.end.column_mut() = display_map.line_len(range.end.row());
18555                let start = range.start.to_point(&display_map);
18556                let end = range.end.to_point(&display_map);
18557                start..end
18558            })
18559            .collect::<Vec<_>>();
18560
18561        self.unfold_ranges(&ranges, true, true, cx);
18562    }
18563
18564    pub fn unfold_at(
18565        &mut self,
18566        buffer_row: MultiBufferRow,
18567        _window: &mut Window,
18568        cx: &mut Context<Self>,
18569    ) {
18570        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18571
18572        let intersection_range = Point::new(buffer_row.0, 0)
18573            ..Point::new(
18574                buffer_row.0,
18575                display_map.buffer_snapshot().line_len(buffer_row),
18576            );
18577
18578        let autoscroll = self
18579            .selections
18580            .all::<Point>(&display_map)
18581            .iter()
18582            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18583
18584        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18585    }
18586
18587    pub fn unfold_all(
18588        &mut self,
18589        _: &actions::UnfoldAll,
18590        _window: &mut Window,
18591        cx: &mut Context<Self>,
18592    ) {
18593        if self.buffer.read(cx).is_singleton() {
18594            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18595            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18596        } else {
18597            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18598                editor
18599                    .update(cx, |editor, cx| {
18600                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18601                            editor.unfold_buffer(buffer_id, cx);
18602                        }
18603                    })
18604                    .ok();
18605            });
18606        }
18607    }
18608
18609    pub fn fold_selected_ranges(
18610        &mut self,
18611        _: &FoldSelectedRanges,
18612        window: &mut Window,
18613        cx: &mut Context<Self>,
18614    ) {
18615        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18616        let selections = self.selections.all_adjusted(&display_map);
18617        let ranges = selections
18618            .into_iter()
18619            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18620            .collect::<Vec<_>>();
18621        self.fold_creases(ranges, true, window, cx);
18622    }
18623
18624    pub fn fold_ranges<T: ToOffset + Clone>(
18625        &mut self,
18626        ranges: Vec<Range<T>>,
18627        auto_scroll: bool,
18628        window: &mut Window,
18629        cx: &mut Context<Self>,
18630    ) {
18631        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18632        let ranges = ranges
18633            .into_iter()
18634            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18635            .collect::<Vec<_>>();
18636        self.fold_creases(ranges, auto_scroll, window, cx);
18637    }
18638
18639    pub fn fold_creases<T: ToOffset + Clone>(
18640        &mut self,
18641        creases: Vec<Crease<T>>,
18642        auto_scroll: bool,
18643        _window: &mut Window,
18644        cx: &mut Context<Self>,
18645    ) {
18646        if creases.is_empty() {
18647            return;
18648        }
18649
18650        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18651
18652        if auto_scroll {
18653            self.request_autoscroll(Autoscroll::fit(), cx);
18654        }
18655
18656        cx.notify();
18657
18658        self.scrollbar_marker_state.dirty = true;
18659        self.folds_did_change(cx);
18660    }
18661
18662    /// Removes any folds whose ranges intersect any of the given ranges.
18663    pub fn unfold_ranges<T: ToOffset + Clone>(
18664        &mut self,
18665        ranges: &[Range<T>],
18666        inclusive: bool,
18667        auto_scroll: bool,
18668        cx: &mut Context<Self>,
18669    ) {
18670        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18671            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18672        });
18673        self.folds_did_change(cx);
18674    }
18675
18676    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18677        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18678            return;
18679        }
18680        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18681        self.display_map.update(cx, |display_map, cx| {
18682            display_map.fold_buffers([buffer_id], cx)
18683        });
18684        cx.emit(EditorEvent::BufferFoldToggled {
18685            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18686            folded: true,
18687        });
18688        cx.notify();
18689    }
18690
18691    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18692        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18693            return;
18694        }
18695        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18696        self.display_map.update(cx, |display_map, cx| {
18697            display_map.unfold_buffers([buffer_id], cx);
18698        });
18699        cx.emit(EditorEvent::BufferFoldToggled {
18700            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18701            folded: false,
18702        });
18703        cx.notify();
18704    }
18705
18706    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18707        self.display_map.read(cx).is_buffer_folded(buffer)
18708    }
18709
18710    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18711        self.display_map.read(cx).folded_buffers()
18712    }
18713
18714    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18715        self.display_map.update(cx, |display_map, cx| {
18716            display_map.disable_header_for_buffer(buffer_id, cx);
18717        });
18718        cx.notify();
18719    }
18720
18721    /// Removes any folds with the given ranges.
18722    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18723        &mut self,
18724        ranges: &[Range<T>],
18725        type_id: TypeId,
18726        auto_scroll: bool,
18727        cx: &mut Context<Self>,
18728    ) {
18729        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18730            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18731        });
18732        self.folds_did_change(cx);
18733    }
18734
18735    fn remove_folds_with<T: ToOffset + Clone>(
18736        &mut self,
18737        ranges: &[Range<T>],
18738        auto_scroll: bool,
18739        cx: &mut Context<Self>,
18740        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18741    ) {
18742        if ranges.is_empty() {
18743            return;
18744        }
18745
18746        let mut buffers_affected = HashSet::default();
18747        let multi_buffer = self.buffer().read(cx);
18748        for range in ranges {
18749            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18750                buffers_affected.insert(buffer.read(cx).remote_id());
18751            };
18752        }
18753
18754        self.display_map.update(cx, update);
18755
18756        if auto_scroll {
18757            self.request_autoscroll(Autoscroll::fit(), cx);
18758        }
18759
18760        cx.notify();
18761        self.scrollbar_marker_state.dirty = true;
18762        self.active_indent_guides_state.dirty = true;
18763    }
18764
18765    pub fn update_renderer_widths(
18766        &mut self,
18767        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18768        cx: &mut Context<Self>,
18769    ) -> bool {
18770        self.display_map
18771            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18772    }
18773
18774    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18775        self.display_map.read(cx).fold_placeholder.clone()
18776    }
18777
18778    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18779        self.buffer.update(cx, |buffer, cx| {
18780            buffer.set_all_diff_hunks_expanded(cx);
18781        });
18782    }
18783
18784    pub fn expand_all_diff_hunks(
18785        &mut self,
18786        _: &ExpandAllDiffHunks,
18787        _window: &mut Window,
18788        cx: &mut Context<Self>,
18789    ) {
18790        self.buffer.update(cx, |buffer, cx| {
18791            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18792        });
18793    }
18794
18795    pub fn collapse_all_diff_hunks(
18796        &mut self,
18797        _: &CollapseAllDiffHunks,
18798        _window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        self.buffer.update(cx, |buffer, cx| {
18802            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18803        });
18804    }
18805
18806    pub fn toggle_selected_diff_hunks(
18807        &mut self,
18808        _: &ToggleSelectedDiffHunks,
18809        _window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        let ranges: Vec<_> = self
18813            .selections
18814            .disjoint_anchors()
18815            .iter()
18816            .map(|s| s.range())
18817            .collect();
18818        self.toggle_diff_hunks_in_ranges(ranges, cx);
18819    }
18820
18821    pub fn diff_hunks_in_ranges<'a>(
18822        &'a self,
18823        ranges: &'a [Range<Anchor>],
18824        buffer: &'a MultiBufferSnapshot,
18825    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18826        ranges.iter().flat_map(move |range| {
18827            let end_excerpt_id = range.end.excerpt_id;
18828            let range = range.to_point(buffer);
18829            let mut peek_end = range.end;
18830            if range.end.row < buffer.max_row().0 {
18831                peek_end = Point::new(range.end.row + 1, 0);
18832            }
18833            buffer
18834                .diff_hunks_in_range(range.start..peek_end)
18835                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18836        })
18837    }
18838
18839    pub fn has_stageable_diff_hunks_in_ranges(
18840        &self,
18841        ranges: &[Range<Anchor>],
18842        snapshot: &MultiBufferSnapshot,
18843    ) -> bool {
18844        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18845        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18846    }
18847
18848    pub fn toggle_staged_selected_diff_hunks(
18849        &mut self,
18850        _: &::git::ToggleStaged,
18851        _: &mut Window,
18852        cx: &mut Context<Self>,
18853    ) {
18854        let snapshot = self.buffer.read(cx).snapshot(cx);
18855        let ranges: Vec<_> = self
18856            .selections
18857            .disjoint_anchors()
18858            .iter()
18859            .map(|s| s.range())
18860            .collect();
18861        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18862        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18863    }
18864
18865    pub fn set_render_diff_hunk_controls(
18866        &mut self,
18867        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18868        cx: &mut Context<Self>,
18869    ) {
18870        self.render_diff_hunk_controls = render_diff_hunk_controls;
18871        cx.notify();
18872    }
18873
18874    pub fn stage_and_next(
18875        &mut self,
18876        _: &::git::StageAndNext,
18877        window: &mut Window,
18878        cx: &mut Context<Self>,
18879    ) {
18880        self.do_stage_or_unstage_and_next(true, window, cx);
18881    }
18882
18883    pub fn unstage_and_next(
18884        &mut self,
18885        _: &::git::UnstageAndNext,
18886        window: &mut Window,
18887        cx: &mut Context<Self>,
18888    ) {
18889        self.do_stage_or_unstage_and_next(false, window, cx);
18890    }
18891
18892    pub fn stage_or_unstage_diff_hunks(
18893        &mut self,
18894        stage: bool,
18895        ranges: Vec<Range<Anchor>>,
18896        cx: &mut Context<Self>,
18897    ) {
18898        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18899        cx.spawn(async move |this, cx| {
18900            task.await?;
18901            this.update(cx, |this, cx| {
18902                let snapshot = this.buffer.read(cx).snapshot(cx);
18903                let chunk_by = this
18904                    .diff_hunks_in_ranges(&ranges, &snapshot)
18905                    .chunk_by(|hunk| hunk.buffer_id);
18906                for (buffer_id, hunks) in &chunk_by {
18907                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18908                }
18909            })
18910        })
18911        .detach_and_log_err(cx);
18912    }
18913
18914    fn save_buffers_for_ranges_if_needed(
18915        &mut self,
18916        ranges: &[Range<Anchor>],
18917        cx: &mut Context<Editor>,
18918    ) -> Task<Result<()>> {
18919        let multibuffer = self.buffer.read(cx);
18920        let snapshot = multibuffer.read(cx);
18921        let buffer_ids: HashSet<_> = ranges
18922            .iter()
18923            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18924            .collect();
18925        drop(snapshot);
18926
18927        let mut buffers = HashSet::default();
18928        for buffer_id in buffer_ids {
18929            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18930                let buffer = buffer_entity.read(cx);
18931                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18932                {
18933                    buffers.insert(buffer_entity);
18934                }
18935            }
18936        }
18937
18938        if let Some(project) = &self.project {
18939            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18940        } else {
18941            Task::ready(Ok(()))
18942        }
18943    }
18944
18945    fn do_stage_or_unstage_and_next(
18946        &mut self,
18947        stage: bool,
18948        window: &mut Window,
18949        cx: &mut Context<Self>,
18950    ) {
18951        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18952
18953        if ranges.iter().any(|range| range.start != range.end) {
18954            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18955            return;
18956        }
18957
18958        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18959        let snapshot = self.snapshot(window, cx);
18960        let position = self
18961            .selections
18962            .newest::<Point>(&snapshot.display_snapshot)
18963            .head();
18964        let mut row = snapshot
18965            .buffer_snapshot()
18966            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18967            .find(|hunk| hunk.row_range.start.0 > position.row)
18968            .map(|hunk| hunk.row_range.start);
18969
18970        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18971        // Outside of the project diff editor, wrap around to the beginning.
18972        if !all_diff_hunks_expanded {
18973            row = row.or_else(|| {
18974                snapshot
18975                    .buffer_snapshot()
18976                    .diff_hunks_in_range(Point::zero()..position)
18977                    .find(|hunk| hunk.row_range.end.0 < position.row)
18978                    .map(|hunk| hunk.row_range.start)
18979            });
18980        }
18981
18982        if let Some(row) = row {
18983            let destination = Point::new(row.0, 0);
18984            let autoscroll = Autoscroll::center();
18985
18986            self.unfold_ranges(&[destination..destination], false, false, cx);
18987            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18988                s.select_ranges([destination..destination]);
18989            });
18990        }
18991    }
18992
18993    fn do_stage_or_unstage(
18994        &self,
18995        stage: bool,
18996        buffer_id: BufferId,
18997        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18998        cx: &mut App,
18999    ) -> Option<()> {
19000        let project = self.project()?;
19001        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19002        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19003        let buffer_snapshot = buffer.read(cx).snapshot();
19004        let file_exists = buffer_snapshot
19005            .file()
19006            .is_some_and(|file| file.disk_state().exists());
19007        diff.update(cx, |diff, cx| {
19008            diff.stage_or_unstage_hunks(
19009                stage,
19010                &hunks
19011                    .map(|hunk| buffer_diff::DiffHunk {
19012                        buffer_range: hunk.buffer_range,
19013                        diff_base_byte_range: hunk.diff_base_byte_range,
19014                        secondary_status: hunk.secondary_status,
19015                        range: Point::zero()..Point::zero(), // unused
19016                    })
19017                    .collect::<Vec<_>>(),
19018                &buffer_snapshot,
19019                file_exists,
19020                cx,
19021            )
19022        });
19023        None
19024    }
19025
19026    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19027        let ranges: Vec<_> = self
19028            .selections
19029            .disjoint_anchors()
19030            .iter()
19031            .map(|s| s.range())
19032            .collect();
19033        self.buffer
19034            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19035    }
19036
19037    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19038        self.buffer.update(cx, |buffer, cx| {
19039            let ranges = vec![Anchor::min()..Anchor::max()];
19040            if !buffer.all_diff_hunks_expanded()
19041                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19042            {
19043                buffer.collapse_diff_hunks(ranges, cx);
19044                true
19045            } else {
19046                false
19047            }
19048        })
19049    }
19050
19051    fn toggle_diff_hunks_in_ranges(
19052        &mut self,
19053        ranges: Vec<Range<Anchor>>,
19054        cx: &mut Context<Editor>,
19055    ) {
19056        self.buffer.update(cx, |buffer, cx| {
19057            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19058            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19059        })
19060    }
19061
19062    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19063        self.buffer.update(cx, |buffer, cx| {
19064            let snapshot = buffer.snapshot(cx);
19065            let excerpt_id = range.end.excerpt_id;
19066            let point_range = range.to_point(&snapshot);
19067            let expand = !buffer.single_hunk_is_expanded(range, cx);
19068            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19069        })
19070    }
19071
19072    pub(crate) fn apply_all_diff_hunks(
19073        &mut self,
19074        _: &ApplyAllDiffHunks,
19075        window: &mut Window,
19076        cx: &mut Context<Self>,
19077    ) {
19078        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19079
19080        let buffers = self.buffer.read(cx).all_buffers();
19081        for branch_buffer in buffers {
19082            branch_buffer.update(cx, |branch_buffer, cx| {
19083                branch_buffer.merge_into_base(Vec::new(), cx);
19084            });
19085        }
19086
19087        if let Some(project) = self.project.clone() {
19088            self.save(
19089                SaveOptions {
19090                    format: true,
19091                    autosave: false,
19092                },
19093                project,
19094                window,
19095                cx,
19096            )
19097            .detach_and_log_err(cx);
19098        }
19099    }
19100
19101    pub(crate) fn apply_selected_diff_hunks(
19102        &mut self,
19103        _: &ApplyDiffHunk,
19104        window: &mut Window,
19105        cx: &mut Context<Self>,
19106    ) {
19107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19108        let snapshot = self.snapshot(window, cx);
19109        let hunks = snapshot.hunks_for_ranges(
19110            self.selections
19111                .all(&snapshot.display_snapshot)
19112                .into_iter()
19113                .map(|selection| selection.range()),
19114        );
19115        let mut ranges_by_buffer = HashMap::default();
19116        self.transact(window, cx, |editor, _window, cx| {
19117            for hunk in hunks {
19118                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19119                    ranges_by_buffer
19120                        .entry(buffer.clone())
19121                        .or_insert_with(Vec::new)
19122                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19123                }
19124            }
19125
19126            for (buffer, ranges) in ranges_by_buffer {
19127                buffer.update(cx, |buffer, cx| {
19128                    buffer.merge_into_base(ranges, cx);
19129                });
19130            }
19131        });
19132
19133        if let Some(project) = self.project.clone() {
19134            self.save(
19135                SaveOptions {
19136                    format: true,
19137                    autosave: false,
19138                },
19139                project,
19140                window,
19141                cx,
19142            )
19143            .detach_and_log_err(cx);
19144        }
19145    }
19146
19147    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19148        if hovered != self.gutter_hovered {
19149            self.gutter_hovered = hovered;
19150            cx.notify();
19151        }
19152    }
19153
19154    pub fn insert_blocks(
19155        &mut self,
19156        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19157        autoscroll: Option<Autoscroll>,
19158        cx: &mut Context<Self>,
19159    ) -> Vec<CustomBlockId> {
19160        let blocks = self
19161            .display_map
19162            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19163        if let Some(autoscroll) = autoscroll {
19164            self.request_autoscroll(autoscroll, cx);
19165        }
19166        cx.notify();
19167        blocks
19168    }
19169
19170    pub fn resize_blocks(
19171        &mut self,
19172        heights: HashMap<CustomBlockId, u32>,
19173        autoscroll: Option<Autoscroll>,
19174        cx: &mut Context<Self>,
19175    ) {
19176        self.display_map
19177            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19178        if let Some(autoscroll) = autoscroll {
19179            self.request_autoscroll(autoscroll, cx);
19180        }
19181        cx.notify();
19182    }
19183
19184    pub fn replace_blocks(
19185        &mut self,
19186        renderers: HashMap<CustomBlockId, RenderBlock>,
19187        autoscroll: Option<Autoscroll>,
19188        cx: &mut Context<Self>,
19189    ) {
19190        self.display_map
19191            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19192        if let Some(autoscroll) = autoscroll {
19193            self.request_autoscroll(autoscroll, cx);
19194        }
19195        cx.notify();
19196    }
19197
19198    pub fn remove_blocks(
19199        &mut self,
19200        block_ids: HashSet<CustomBlockId>,
19201        autoscroll: Option<Autoscroll>,
19202        cx: &mut Context<Self>,
19203    ) {
19204        self.display_map.update(cx, |display_map, cx| {
19205            display_map.remove_blocks(block_ids, cx)
19206        });
19207        if let Some(autoscroll) = autoscroll {
19208            self.request_autoscroll(autoscroll, cx);
19209        }
19210        cx.notify();
19211    }
19212
19213    pub fn row_for_block(
19214        &self,
19215        block_id: CustomBlockId,
19216        cx: &mut Context<Self>,
19217    ) -> Option<DisplayRow> {
19218        self.display_map
19219            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19220    }
19221
19222    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19223        self.focused_block = Some(focused_block);
19224    }
19225
19226    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19227        self.focused_block.take()
19228    }
19229
19230    pub fn insert_creases(
19231        &mut self,
19232        creases: impl IntoIterator<Item = Crease<Anchor>>,
19233        cx: &mut Context<Self>,
19234    ) -> Vec<CreaseId> {
19235        self.display_map
19236            .update(cx, |map, cx| map.insert_creases(creases, cx))
19237    }
19238
19239    pub fn remove_creases(
19240        &mut self,
19241        ids: impl IntoIterator<Item = CreaseId>,
19242        cx: &mut Context<Self>,
19243    ) -> Vec<(CreaseId, Range<Anchor>)> {
19244        self.display_map
19245            .update(cx, |map, cx| map.remove_creases(ids, cx))
19246    }
19247
19248    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19249        self.display_map
19250            .update(cx, |map, cx| map.snapshot(cx))
19251            .longest_row()
19252    }
19253
19254    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19255        self.display_map
19256            .update(cx, |map, cx| map.snapshot(cx))
19257            .max_point()
19258    }
19259
19260    pub fn text(&self, cx: &App) -> String {
19261        self.buffer.read(cx).read(cx).text()
19262    }
19263
19264    pub fn is_empty(&self, cx: &App) -> bool {
19265        self.buffer.read(cx).read(cx).is_empty()
19266    }
19267
19268    pub fn text_option(&self, cx: &App) -> Option<String> {
19269        let text = self.text(cx);
19270        let text = text.trim();
19271
19272        if text.is_empty() {
19273            return None;
19274        }
19275
19276        Some(text.to_string())
19277    }
19278
19279    pub fn set_text(
19280        &mut self,
19281        text: impl Into<Arc<str>>,
19282        window: &mut Window,
19283        cx: &mut Context<Self>,
19284    ) {
19285        self.transact(window, cx, |this, _, cx| {
19286            this.buffer
19287                .read(cx)
19288                .as_singleton()
19289                .expect("you can only call set_text on editors for singleton buffers")
19290                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19291        });
19292    }
19293
19294    pub fn display_text(&self, cx: &mut App) -> String {
19295        self.display_map
19296            .update(cx, |map, cx| map.snapshot(cx))
19297            .text()
19298    }
19299
19300    fn create_minimap(
19301        &self,
19302        minimap_settings: MinimapSettings,
19303        window: &mut Window,
19304        cx: &mut Context<Self>,
19305    ) -> Option<Entity<Self>> {
19306        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19307            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19308    }
19309
19310    fn initialize_new_minimap(
19311        &self,
19312        minimap_settings: MinimapSettings,
19313        window: &mut Window,
19314        cx: &mut Context<Self>,
19315    ) -> Entity<Self> {
19316        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19317
19318        let mut minimap = Editor::new_internal(
19319            EditorMode::Minimap {
19320                parent: cx.weak_entity(),
19321            },
19322            self.buffer.clone(),
19323            None,
19324            Some(self.display_map.clone()),
19325            window,
19326            cx,
19327        );
19328        minimap.scroll_manager.clone_state(&self.scroll_manager);
19329        minimap.set_text_style_refinement(TextStyleRefinement {
19330            font_size: Some(MINIMAP_FONT_SIZE),
19331            font_weight: Some(MINIMAP_FONT_WEIGHT),
19332            ..Default::default()
19333        });
19334        minimap.update_minimap_configuration(minimap_settings, cx);
19335        cx.new(|_| minimap)
19336    }
19337
19338    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19339        let current_line_highlight = minimap_settings
19340            .current_line_highlight
19341            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19342        self.set_current_line_highlight(Some(current_line_highlight));
19343    }
19344
19345    pub fn minimap(&self) -> Option<&Entity<Self>> {
19346        self.minimap
19347            .as_ref()
19348            .filter(|_| self.minimap_visibility.visible())
19349    }
19350
19351    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19352        let mut wrap_guides = smallvec![];
19353
19354        if self.show_wrap_guides == Some(false) {
19355            return wrap_guides;
19356        }
19357
19358        let settings = self.buffer.read(cx).language_settings(cx);
19359        if settings.show_wrap_guides {
19360            match self.soft_wrap_mode(cx) {
19361                SoftWrap::Column(soft_wrap) => {
19362                    wrap_guides.push((soft_wrap as usize, true));
19363                }
19364                SoftWrap::Bounded(soft_wrap) => {
19365                    wrap_guides.push((soft_wrap as usize, true));
19366                }
19367                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19368            }
19369            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19370        }
19371
19372        wrap_guides
19373    }
19374
19375    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19376        let settings = self.buffer.read(cx).language_settings(cx);
19377        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19378        match mode {
19379            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19380                SoftWrap::None
19381            }
19382            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19383            language_settings::SoftWrap::PreferredLineLength => {
19384                SoftWrap::Column(settings.preferred_line_length)
19385            }
19386            language_settings::SoftWrap::Bounded => {
19387                SoftWrap::Bounded(settings.preferred_line_length)
19388            }
19389        }
19390    }
19391
19392    pub fn set_soft_wrap_mode(
19393        &mut self,
19394        mode: language_settings::SoftWrap,
19395
19396        cx: &mut Context<Self>,
19397    ) {
19398        self.soft_wrap_mode_override = Some(mode);
19399        cx.notify();
19400    }
19401
19402    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19403        self.hard_wrap = hard_wrap;
19404        cx.notify();
19405    }
19406
19407    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19408        self.text_style_refinement = Some(style);
19409    }
19410
19411    /// called by the Element so we know what style we were most recently rendered with.
19412    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19413        // We intentionally do not inform the display map about the minimap style
19414        // so that wrapping is not recalculated and stays consistent for the editor
19415        // and its linked minimap.
19416        if !self.mode.is_minimap() {
19417            let font = style.text.font();
19418            let font_size = style.text.font_size.to_pixels(window.rem_size());
19419            let display_map = self
19420                .placeholder_display_map
19421                .as_ref()
19422                .filter(|_| self.is_empty(cx))
19423                .unwrap_or(&self.display_map);
19424
19425            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19426        }
19427        self.style = Some(style);
19428    }
19429
19430    pub fn style(&self) -> Option<&EditorStyle> {
19431        self.style.as_ref()
19432    }
19433
19434    // Called by the element. This method is not designed to be called outside of the editor
19435    // element's layout code because it does not notify when rewrapping is computed synchronously.
19436    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19437        if self.is_empty(cx) {
19438            self.placeholder_display_map
19439                .as_ref()
19440                .map_or(false, |display_map| {
19441                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19442                })
19443        } else {
19444            self.display_map
19445                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19446        }
19447    }
19448
19449    pub fn set_soft_wrap(&mut self) {
19450        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19451    }
19452
19453    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19454        if self.soft_wrap_mode_override.is_some() {
19455            self.soft_wrap_mode_override.take();
19456        } else {
19457            let soft_wrap = match self.soft_wrap_mode(cx) {
19458                SoftWrap::GitDiff => return,
19459                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19460                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19461                    language_settings::SoftWrap::None
19462                }
19463            };
19464            self.soft_wrap_mode_override = Some(soft_wrap);
19465        }
19466        cx.notify();
19467    }
19468
19469    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19470        let Some(workspace) = self.workspace() else {
19471            return;
19472        };
19473        let fs = workspace.read(cx).app_state().fs.clone();
19474        let current_show = TabBarSettings::get_global(cx).show;
19475        update_settings_file(fs, cx, move |setting, _| {
19476            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19477        });
19478    }
19479
19480    pub fn toggle_indent_guides(
19481        &mut self,
19482        _: &ToggleIndentGuides,
19483        _: &mut Window,
19484        cx: &mut Context<Self>,
19485    ) {
19486        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19487            self.buffer
19488                .read(cx)
19489                .language_settings(cx)
19490                .indent_guides
19491                .enabled
19492        });
19493        self.show_indent_guides = Some(!currently_enabled);
19494        cx.notify();
19495    }
19496
19497    fn should_show_indent_guides(&self) -> Option<bool> {
19498        self.show_indent_guides
19499    }
19500
19501    pub fn toggle_line_numbers(
19502        &mut self,
19503        _: &ToggleLineNumbers,
19504        _: &mut Window,
19505        cx: &mut Context<Self>,
19506    ) {
19507        let mut editor_settings = EditorSettings::get_global(cx).clone();
19508        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19509        EditorSettings::override_global(editor_settings, cx);
19510    }
19511
19512    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19513        if let Some(show_line_numbers) = self.show_line_numbers {
19514            return show_line_numbers;
19515        }
19516        EditorSettings::get_global(cx).gutter.line_numbers
19517    }
19518
19519    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19520        self.use_relative_line_numbers
19521            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19522    }
19523
19524    pub fn toggle_relative_line_numbers(
19525        &mut self,
19526        _: &ToggleRelativeLineNumbers,
19527        _: &mut Window,
19528        cx: &mut Context<Self>,
19529    ) {
19530        let is_relative = self.should_use_relative_line_numbers(cx);
19531        self.set_relative_line_number(Some(!is_relative), cx)
19532    }
19533
19534    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19535        self.use_relative_line_numbers = is_relative;
19536        cx.notify();
19537    }
19538
19539    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19540        self.show_gutter = show_gutter;
19541        cx.notify();
19542    }
19543
19544    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19545        self.show_scrollbars = ScrollbarAxes {
19546            horizontal: show,
19547            vertical: show,
19548        };
19549        cx.notify();
19550    }
19551
19552    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19553        self.show_scrollbars.vertical = show;
19554        cx.notify();
19555    }
19556
19557    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19558        self.show_scrollbars.horizontal = show;
19559        cx.notify();
19560    }
19561
19562    pub fn set_minimap_visibility(
19563        &mut self,
19564        minimap_visibility: MinimapVisibility,
19565        window: &mut Window,
19566        cx: &mut Context<Self>,
19567    ) {
19568        if self.minimap_visibility != minimap_visibility {
19569            if minimap_visibility.visible() && self.minimap.is_none() {
19570                let minimap_settings = EditorSettings::get_global(cx).minimap;
19571                self.minimap =
19572                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19573            }
19574            self.minimap_visibility = minimap_visibility;
19575            cx.notify();
19576        }
19577    }
19578
19579    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19580        self.set_show_scrollbars(false, cx);
19581        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19582    }
19583
19584    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19585        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19586    }
19587
19588    /// Normally the text in full mode and auto height editors is padded on the
19589    /// left side by roughly half a character width for improved hit testing.
19590    ///
19591    /// Use this method to disable this for cases where this is not wanted (e.g.
19592    /// if you want to align the editor text with some other text above or below)
19593    /// or if you want to add this padding to single-line editors.
19594    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19595        self.offset_content = offset_content;
19596        cx.notify();
19597    }
19598
19599    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19600        self.show_line_numbers = Some(show_line_numbers);
19601        cx.notify();
19602    }
19603
19604    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19605        self.disable_expand_excerpt_buttons = true;
19606        cx.notify();
19607    }
19608
19609    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19610        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19611        cx.notify();
19612    }
19613
19614    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19615        self.show_code_actions = Some(show_code_actions);
19616        cx.notify();
19617    }
19618
19619    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19620        self.show_runnables = Some(show_runnables);
19621        cx.notify();
19622    }
19623
19624    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19625        self.show_breakpoints = Some(show_breakpoints);
19626        cx.notify();
19627    }
19628
19629    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19630        if self.display_map.read(cx).masked != masked {
19631            self.display_map.update(cx, |map, _| map.masked = masked);
19632        }
19633        cx.notify()
19634    }
19635
19636    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19637        self.show_wrap_guides = Some(show_wrap_guides);
19638        cx.notify();
19639    }
19640
19641    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19642        self.show_indent_guides = Some(show_indent_guides);
19643        cx.notify();
19644    }
19645
19646    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19647        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19648            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19649                && let Some(dir) = file.abs_path(cx).parent()
19650            {
19651                return Some(dir.to_owned());
19652            }
19653        }
19654
19655        None
19656    }
19657
19658    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19659        self.active_excerpt(cx)?
19660            .1
19661            .read(cx)
19662            .file()
19663            .and_then(|f| f.as_local())
19664    }
19665
19666    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19667        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19668            let buffer = buffer.read(cx);
19669            if let Some(project_path) = buffer.project_path(cx) {
19670                let project = self.project()?.read(cx);
19671                project.absolute_path(&project_path, cx)
19672            } else {
19673                buffer
19674                    .file()
19675                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19676            }
19677        })
19678    }
19679
19680    pub fn reveal_in_finder(
19681        &mut self,
19682        _: &RevealInFileManager,
19683        _window: &mut Window,
19684        cx: &mut Context<Self>,
19685    ) {
19686        if let Some(target) = self.target_file(cx) {
19687            cx.reveal_path(&target.abs_path(cx));
19688        }
19689    }
19690
19691    pub fn copy_path(
19692        &mut self,
19693        _: &zed_actions::workspace::CopyPath,
19694        _window: &mut Window,
19695        cx: &mut Context<Self>,
19696    ) {
19697        if let Some(path) = self.target_file_abs_path(cx)
19698            && let Some(path) = path.to_str()
19699        {
19700            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19701        } else {
19702            cx.propagate();
19703        }
19704    }
19705
19706    pub fn copy_relative_path(
19707        &mut self,
19708        _: &zed_actions::workspace::CopyRelativePath,
19709        _window: &mut Window,
19710        cx: &mut Context<Self>,
19711    ) {
19712        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19713            let project = self.project()?.read(cx);
19714            let path = buffer.read(cx).file()?.path();
19715            let path = path.display(project.path_style(cx));
19716            Some(path)
19717        }) {
19718            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19719        } else {
19720            cx.propagate();
19721        }
19722    }
19723
19724    /// Returns the project path for the editor's buffer, if any buffer is
19725    /// opened in the editor.
19726    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19727        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19728            buffer.read(cx).project_path(cx)
19729        } else {
19730            None
19731        }
19732    }
19733
19734    // Returns true if the editor handled a go-to-line request
19735    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19736        maybe!({
19737            let breakpoint_store = self.breakpoint_store.as_ref()?;
19738
19739            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19740            else {
19741                self.clear_row_highlights::<ActiveDebugLine>();
19742                return None;
19743            };
19744
19745            let position = active_stack_frame.position;
19746            let buffer_id = position.buffer_id?;
19747            let snapshot = self
19748                .project
19749                .as_ref()?
19750                .read(cx)
19751                .buffer_for_id(buffer_id, cx)?
19752                .read(cx)
19753                .snapshot();
19754
19755            let mut handled = false;
19756            for (id, ExcerptRange { context, .. }) in
19757                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19758            {
19759                if context.start.cmp(&position, &snapshot).is_ge()
19760                    || context.end.cmp(&position, &snapshot).is_lt()
19761                {
19762                    continue;
19763                }
19764                let snapshot = self.buffer.read(cx).snapshot(cx);
19765                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19766
19767                handled = true;
19768                self.clear_row_highlights::<ActiveDebugLine>();
19769
19770                self.go_to_line::<ActiveDebugLine>(
19771                    multibuffer_anchor,
19772                    Some(cx.theme().colors().editor_debugger_active_line_background),
19773                    window,
19774                    cx,
19775                );
19776
19777                cx.notify();
19778            }
19779
19780            handled.then_some(())
19781        })
19782        .is_some()
19783    }
19784
19785    pub fn copy_file_name_without_extension(
19786        &mut self,
19787        _: &CopyFileNameWithoutExtension,
19788        _: &mut Window,
19789        cx: &mut Context<Self>,
19790    ) {
19791        if let Some(file) = self.target_file(cx)
19792            && let Some(file_stem) = file.path().file_stem()
19793        {
19794            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19795        }
19796    }
19797
19798    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19799        if let Some(file) = self.target_file(cx)
19800            && let Some(name) = file.path().file_name()
19801        {
19802            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19803        }
19804    }
19805
19806    pub fn toggle_git_blame(
19807        &mut self,
19808        _: &::git::Blame,
19809        window: &mut Window,
19810        cx: &mut Context<Self>,
19811    ) {
19812        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19813
19814        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19815            self.start_git_blame(true, window, cx);
19816        }
19817
19818        cx.notify();
19819    }
19820
19821    pub fn toggle_git_blame_inline(
19822        &mut self,
19823        _: &ToggleGitBlameInline,
19824        window: &mut Window,
19825        cx: &mut Context<Self>,
19826    ) {
19827        self.toggle_git_blame_inline_internal(true, window, cx);
19828        cx.notify();
19829    }
19830
19831    pub fn open_git_blame_commit(
19832        &mut self,
19833        _: &OpenGitBlameCommit,
19834        window: &mut Window,
19835        cx: &mut Context<Self>,
19836    ) {
19837        self.open_git_blame_commit_internal(window, cx);
19838    }
19839
19840    fn open_git_blame_commit_internal(
19841        &mut self,
19842        window: &mut Window,
19843        cx: &mut Context<Self>,
19844    ) -> Option<()> {
19845        let blame = self.blame.as_ref()?;
19846        let snapshot = self.snapshot(window, cx);
19847        let cursor = self
19848            .selections
19849            .newest::<Point>(&snapshot.display_snapshot)
19850            .head();
19851        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19852        let (_, blame_entry) = blame
19853            .update(cx, |blame, cx| {
19854                blame
19855                    .blame_for_rows(
19856                        &[RowInfo {
19857                            buffer_id: Some(buffer.remote_id()),
19858                            buffer_row: Some(point.row),
19859                            ..Default::default()
19860                        }],
19861                        cx,
19862                    )
19863                    .next()
19864            })
19865            .flatten()?;
19866        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19867        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19868        let workspace = self.workspace()?.downgrade();
19869        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19870        None
19871    }
19872
19873    pub fn git_blame_inline_enabled(&self) -> bool {
19874        self.git_blame_inline_enabled
19875    }
19876
19877    pub fn toggle_selection_menu(
19878        &mut self,
19879        _: &ToggleSelectionMenu,
19880        _: &mut Window,
19881        cx: &mut Context<Self>,
19882    ) {
19883        self.show_selection_menu = self
19884            .show_selection_menu
19885            .map(|show_selections_menu| !show_selections_menu)
19886            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19887
19888        cx.notify();
19889    }
19890
19891    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19892        self.show_selection_menu
19893            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19894    }
19895
19896    fn start_git_blame(
19897        &mut self,
19898        user_triggered: bool,
19899        window: &mut Window,
19900        cx: &mut Context<Self>,
19901    ) {
19902        if let Some(project) = self.project() {
19903            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19904                && buffer.read(cx).file().is_none()
19905            {
19906                return;
19907            }
19908
19909            let focused = self.focus_handle(cx).contains_focused(window, cx);
19910
19911            let project = project.clone();
19912            let blame = cx
19913                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19914            self.blame_subscription =
19915                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19916            self.blame = Some(blame);
19917        }
19918    }
19919
19920    fn toggle_git_blame_inline_internal(
19921        &mut self,
19922        user_triggered: bool,
19923        window: &mut Window,
19924        cx: &mut Context<Self>,
19925    ) {
19926        if self.git_blame_inline_enabled {
19927            self.git_blame_inline_enabled = false;
19928            self.show_git_blame_inline = false;
19929            self.show_git_blame_inline_delay_task.take();
19930        } else {
19931            self.git_blame_inline_enabled = true;
19932            self.start_git_blame_inline(user_triggered, window, cx);
19933        }
19934
19935        cx.notify();
19936    }
19937
19938    fn start_git_blame_inline(
19939        &mut self,
19940        user_triggered: bool,
19941        window: &mut Window,
19942        cx: &mut Context<Self>,
19943    ) {
19944        self.start_git_blame(user_triggered, window, cx);
19945
19946        if ProjectSettings::get_global(cx)
19947            .git
19948            .inline_blame_delay()
19949            .is_some()
19950        {
19951            self.start_inline_blame_timer(window, cx);
19952        } else {
19953            self.show_git_blame_inline = true
19954        }
19955    }
19956
19957    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19958        self.blame.as_ref()
19959    }
19960
19961    pub fn show_git_blame_gutter(&self) -> bool {
19962        self.show_git_blame_gutter
19963    }
19964
19965    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19966        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19967    }
19968
19969    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19970        self.show_git_blame_inline
19971            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19972            && !self.newest_selection_head_on_empty_line(cx)
19973            && self.has_blame_entries(cx)
19974    }
19975
19976    fn has_blame_entries(&self, cx: &App) -> bool {
19977        self.blame()
19978            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19979    }
19980
19981    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19982        let cursor_anchor = self.selections.newest_anchor().head();
19983
19984        let snapshot = self.buffer.read(cx).snapshot(cx);
19985        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19986
19987        snapshot.line_len(buffer_row) == 0
19988    }
19989
19990    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19991        let buffer_and_selection = maybe!({
19992            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19993            let selection_range = selection.range();
19994
19995            let multi_buffer = self.buffer().read(cx);
19996            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19997            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19998
19999            let (buffer, range, _) = if selection.reversed {
20000                buffer_ranges.first()
20001            } else {
20002                buffer_ranges.last()
20003            }?;
20004
20005            let selection = text::ToPoint::to_point(&range.start, buffer).row
20006                ..text::ToPoint::to_point(&range.end, buffer).row;
20007            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20008        });
20009
20010        let Some((buffer, selection)) = buffer_and_selection else {
20011            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20012        };
20013
20014        let Some(project) = self.project() else {
20015            return Task::ready(Err(anyhow!("editor does not have project")));
20016        };
20017
20018        project.update(cx, |project, cx| {
20019            project.get_permalink_to_line(&buffer, selection, cx)
20020        })
20021    }
20022
20023    pub fn copy_permalink_to_line(
20024        &mut self,
20025        _: &CopyPermalinkToLine,
20026        window: &mut Window,
20027        cx: &mut Context<Self>,
20028    ) {
20029        let permalink_task = self.get_permalink_to_line(cx);
20030        let workspace = self.workspace();
20031
20032        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20033            Ok(permalink) => {
20034                cx.update(|_, cx| {
20035                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20036                })
20037                .ok();
20038            }
20039            Err(err) => {
20040                let message = format!("Failed to copy permalink: {err}");
20041
20042                anyhow::Result::<()>::Err(err).log_err();
20043
20044                if let Some(workspace) = workspace {
20045                    workspace
20046                        .update_in(cx, |workspace, _, cx| {
20047                            struct CopyPermalinkToLine;
20048
20049                            workspace.show_toast(
20050                                Toast::new(
20051                                    NotificationId::unique::<CopyPermalinkToLine>(),
20052                                    message,
20053                                ),
20054                                cx,
20055                            )
20056                        })
20057                        .ok();
20058                }
20059            }
20060        })
20061        .detach();
20062    }
20063
20064    pub fn copy_file_location(
20065        &mut self,
20066        _: &CopyFileLocation,
20067        _: &mut Window,
20068        cx: &mut Context<Self>,
20069    ) {
20070        let selection = self
20071            .selections
20072            .newest::<Point>(&self.display_snapshot(cx))
20073            .start
20074            .row
20075            + 1;
20076        if let Some(file) = self.target_file(cx) {
20077            let path = file.path().display(file.path_style(cx));
20078            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20079        }
20080    }
20081
20082    pub fn open_permalink_to_line(
20083        &mut self,
20084        _: &OpenPermalinkToLine,
20085        window: &mut Window,
20086        cx: &mut Context<Self>,
20087    ) {
20088        let permalink_task = self.get_permalink_to_line(cx);
20089        let workspace = self.workspace();
20090
20091        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20092            Ok(permalink) => {
20093                cx.update(|_, cx| {
20094                    cx.open_url(permalink.as_ref());
20095                })
20096                .ok();
20097            }
20098            Err(err) => {
20099                let message = format!("Failed to open permalink: {err}");
20100
20101                anyhow::Result::<()>::Err(err).log_err();
20102
20103                if let Some(workspace) = workspace {
20104                    workspace
20105                        .update(cx, |workspace, cx| {
20106                            struct OpenPermalinkToLine;
20107
20108                            workspace.show_toast(
20109                                Toast::new(
20110                                    NotificationId::unique::<OpenPermalinkToLine>(),
20111                                    message,
20112                                ),
20113                                cx,
20114                            )
20115                        })
20116                        .ok();
20117                }
20118            }
20119        })
20120        .detach();
20121    }
20122
20123    pub fn insert_uuid_v4(
20124        &mut self,
20125        _: &InsertUuidV4,
20126        window: &mut Window,
20127        cx: &mut Context<Self>,
20128    ) {
20129        self.insert_uuid(UuidVersion::V4, window, cx);
20130    }
20131
20132    pub fn insert_uuid_v7(
20133        &mut self,
20134        _: &InsertUuidV7,
20135        window: &mut Window,
20136        cx: &mut Context<Self>,
20137    ) {
20138        self.insert_uuid(UuidVersion::V7, window, cx);
20139    }
20140
20141    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20143        self.transact(window, cx, |this, window, cx| {
20144            let edits = this
20145                .selections
20146                .all::<Point>(&this.display_snapshot(cx))
20147                .into_iter()
20148                .map(|selection| {
20149                    let uuid = match version {
20150                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20151                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20152                    };
20153
20154                    (selection.range(), uuid.to_string())
20155                });
20156            this.edit(edits, cx);
20157            this.refresh_edit_prediction(true, false, window, cx);
20158        });
20159    }
20160
20161    pub fn open_selections_in_multibuffer(
20162        &mut self,
20163        _: &OpenSelectionsInMultibuffer,
20164        window: &mut Window,
20165        cx: &mut Context<Self>,
20166    ) {
20167        let multibuffer = self.buffer.read(cx);
20168
20169        let Some(buffer) = multibuffer.as_singleton() else {
20170            return;
20171        };
20172
20173        let Some(workspace) = self.workspace() else {
20174            return;
20175        };
20176
20177        let title = multibuffer.title(cx).to_string();
20178
20179        let locations = self
20180            .selections
20181            .all_anchors(cx)
20182            .iter()
20183            .map(|selection| {
20184                (
20185                    buffer.clone(),
20186                    (selection.start.text_anchor..selection.end.text_anchor)
20187                        .to_point(buffer.read(cx)),
20188                )
20189            })
20190            .into_group_map();
20191
20192        cx.spawn_in(window, async move |_, cx| {
20193            workspace.update_in(cx, |workspace, window, cx| {
20194                Self::open_locations_in_multibuffer(
20195                    workspace,
20196                    locations,
20197                    format!("Selections for '{title}'"),
20198                    false,
20199                    MultibufferSelectionMode::All,
20200                    window,
20201                    cx,
20202                );
20203            })
20204        })
20205        .detach();
20206    }
20207
20208    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20209    /// last highlight added will be used.
20210    ///
20211    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20212    pub fn highlight_rows<T: 'static>(
20213        &mut self,
20214        range: Range<Anchor>,
20215        color: Hsla,
20216        options: RowHighlightOptions,
20217        cx: &mut Context<Self>,
20218    ) {
20219        let snapshot = self.buffer().read(cx).snapshot(cx);
20220        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20221        let ix = row_highlights.binary_search_by(|highlight| {
20222            Ordering::Equal
20223                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20224                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20225        });
20226
20227        if let Err(mut ix) = ix {
20228            let index = post_inc(&mut self.highlight_order);
20229
20230            // If this range intersects with the preceding highlight, then merge it with
20231            // the preceding highlight. Otherwise insert a new highlight.
20232            let mut merged = false;
20233            if ix > 0 {
20234                let prev_highlight = &mut row_highlights[ix - 1];
20235                if prev_highlight
20236                    .range
20237                    .end
20238                    .cmp(&range.start, &snapshot)
20239                    .is_ge()
20240                {
20241                    ix -= 1;
20242                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20243                        prev_highlight.range.end = range.end;
20244                    }
20245                    merged = true;
20246                    prev_highlight.index = index;
20247                    prev_highlight.color = color;
20248                    prev_highlight.options = options;
20249                }
20250            }
20251
20252            if !merged {
20253                row_highlights.insert(
20254                    ix,
20255                    RowHighlight {
20256                        range,
20257                        index,
20258                        color,
20259                        options,
20260                        type_id: TypeId::of::<T>(),
20261                    },
20262                );
20263            }
20264
20265            // If any of the following highlights intersect with this one, merge them.
20266            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20267                let highlight = &row_highlights[ix];
20268                if next_highlight
20269                    .range
20270                    .start
20271                    .cmp(&highlight.range.end, &snapshot)
20272                    .is_le()
20273                {
20274                    if next_highlight
20275                        .range
20276                        .end
20277                        .cmp(&highlight.range.end, &snapshot)
20278                        .is_gt()
20279                    {
20280                        row_highlights[ix].range.end = next_highlight.range.end;
20281                    }
20282                    row_highlights.remove(ix + 1);
20283                } else {
20284                    break;
20285                }
20286            }
20287        }
20288    }
20289
20290    /// Remove any highlighted row ranges of the given type that intersect the
20291    /// given ranges.
20292    pub fn remove_highlighted_rows<T: 'static>(
20293        &mut self,
20294        ranges_to_remove: Vec<Range<Anchor>>,
20295        cx: &mut Context<Self>,
20296    ) {
20297        let snapshot = self.buffer().read(cx).snapshot(cx);
20298        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20299        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20300        row_highlights.retain(|highlight| {
20301            while let Some(range_to_remove) = ranges_to_remove.peek() {
20302                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20303                    Ordering::Less | Ordering::Equal => {
20304                        ranges_to_remove.next();
20305                    }
20306                    Ordering::Greater => {
20307                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20308                            Ordering::Less | Ordering::Equal => {
20309                                return false;
20310                            }
20311                            Ordering::Greater => break,
20312                        }
20313                    }
20314                }
20315            }
20316
20317            true
20318        })
20319    }
20320
20321    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20322    pub fn clear_row_highlights<T: 'static>(&mut self) {
20323        self.highlighted_rows.remove(&TypeId::of::<T>());
20324    }
20325
20326    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20327    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20328        self.highlighted_rows
20329            .get(&TypeId::of::<T>())
20330            .map_or(&[] as &[_], |vec| vec.as_slice())
20331            .iter()
20332            .map(|highlight| (highlight.range.clone(), highlight.color))
20333    }
20334
20335    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20336    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20337    /// Allows to ignore certain kinds of highlights.
20338    pub fn highlighted_display_rows(
20339        &self,
20340        window: &mut Window,
20341        cx: &mut App,
20342    ) -> BTreeMap<DisplayRow, LineHighlight> {
20343        let snapshot = self.snapshot(window, cx);
20344        let mut used_highlight_orders = HashMap::default();
20345        self.highlighted_rows
20346            .iter()
20347            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20348            .fold(
20349                BTreeMap::<DisplayRow, LineHighlight>::new(),
20350                |mut unique_rows, highlight| {
20351                    let start = highlight.range.start.to_display_point(&snapshot);
20352                    let end = highlight.range.end.to_display_point(&snapshot);
20353                    let start_row = start.row().0;
20354                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20355                        && end.column() == 0
20356                    {
20357                        end.row().0.saturating_sub(1)
20358                    } else {
20359                        end.row().0
20360                    };
20361                    for row in start_row..=end_row {
20362                        let used_index =
20363                            used_highlight_orders.entry(row).or_insert(highlight.index);
20364                        if highlight.index >= *used_index {
20365                            *used_index = highlight.index;
20366                            unique_rows.insert(
20367                                DisplayRow(row),
20368                                LineHighlight {
20369                                    include_gutter: highlight.options.include_gutter,
20370                                    border: None,
20371                                    background: highlight.color.into(),
20372                                    type_id: Some(highlight.type_id),
20373                                },
20374                            );
20375                        }
20376                    }
20377                    unique_rows
20378                },
20379            )
20380    }
20381
20382    pub fn highlighted_display_row_for_autoscroll(
20383        &self,
20384        snapshot: &DisplaySnapshot,
20385    ) -> Option<DisplayRow> {
20386        self.highlighted_rows
20387            .values()
20388            .flat_map(|highlighted_rows| highlighted_rows.iter())
20389            .filter_map(|highlight| {
20390                if highlight.options.autoscroll {
20391                    Some(highlight.range.start.to_display_point(snapshot).row())
20392                } else {
20393                    None
20394                }
20395            })
20396            .min()
20397    }
20398
20399    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20400        self.highlight_background::<SearchWithinRange>(
20401            ranges,
20402            |colors| colors.colors().editor_document_highlight_read_background,
20403            cx,
20404        )
20405    }
20406
20407    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20408        self.breadcrumb_header = Some(new_header);
20409    }
20410
20411    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20412        self.clear_background_highlights::<SearchWithinRange>(cx);
20413    }
20414
20415    pub fn highlight_background<T: 'static>(
20416        &mut self,
20417        ranges: &[Range<Anchor>],
20418        color_fetcher: fn(&Theme) -> Hsla,
20419        cx: &mut Context<Self>,
20420    ) {
20421        self.background_highlights.insert(
20422            HighlightKey::Type(TypeId::of::<T>()),
20423            (color_fetcher, Arc::from(ranges)),
20424        );
20425        self.scrollbar_marker_state.dirty = true;
20426        cx.notify();
20427    }
20428
20429    pub fn highlight_background_key<T: 'static>(
20430        &mut self,
20431        key: usize,
20432        ranges: &[Range<Anchor>],
20433        color_fetcher: fn(&Theme) -> Hsla,
20434        cx: &mut Context<Self>,
20435    ) {
20436        self.background_highlights.insert(
20437            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20438            (color_fetcher, Arc::from(ranges)),
20439        );
20440        self.scrollbar_marker_state.dirty = true;
20441        cx.notify();
20442    }
20443
20444    pub fn clear_background_highlights<T: 'static>(
20445        &mut self,
20446        cx: &mut Context<Self>,
20447    ) -> Option<BackgroundHighlight> {
20448        let text_highlights = self
20449            .background_highlights
20450            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20451        if !text_highlights.1.is_empty() {
20452            self.scrollbar_marker_state.dirty = true;
20453            cx.notify();
20454        }
20455        Some(text_highlights)
20456    }
20457
20458    pub fn highlight_gutter<T: 'static>(
20459        &mut self,
20460        ranges: impl Into<Vec<Range<Anchor>>>,
20461        color_fetcher: fn(&App) -> Hsla,
20462        cx: &mut Context<Self>,
20463    ) {
20464        self.gutter_highlights
20465            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20466        cx.notify();
20467    }
20468
20469    pub fn clear_gutter_highlights<T: 'static>(
20470        &mut self,
20471        cx: &mut Context<Self>,
20472    ) -> Option<GutterHighlight> {
20473        cx.notify();
20474        self.gutter_highlights.remove(&TypeId::of::<T>())
20475    }
20476
20477    pub fn insert_gutter_highlight<T: 'static>(
20478        &mut self,
20479        range: Range<Anchor>,
20480        color_fetcher: fn(&App) -> Hsla,
20481        cx: &mut Context<Self>,
20482    ) {
20483        let snapshot = self.buffer().read(cx).snapshot(cx);
20484        let mut highlights = self
20485            .gutter_highlights
20486            .remove(&TypeId::of::<T>())
20487            .map(|(_, highlights)| highlights)
20488            .unwrap_or_default();
20489        let ix = highlights.binary_search_by(|highlight| {
20490            Ordering::Equal
20491                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20492                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20493        });
20494        if let Err(ix) = ix {
20495            highlights.insert(ix, range);
20496        }
20497        self.gutter_highlights
20498            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20499    }
20500
20501    pub fn remove_gutter_highlights<T: 'static>(
20502        &mut self,
20503        ranges_to_remove: Vec<Range<Anchor>>,
20504        cx: &mut Context<Self>,
20505    ) {
20506        let snapshot = self.buffer().read(cx).snapshot(cx);
20507        let Some((color_fetcher, mut gutter_highlights)) =
20508            self.gutter_highlights.remove(&TypeId::of::<T>())
20509        else {
20510            return;
20511        };
20512        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20513        gutter_highlights.retain(|highlight| {
20514            while let Some(range_to_remove) = ranges_to_remove.peek() {
20515                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20516                    Ordering::Less | Ordering::Equal => {
20517                        ranges_to_remove.next();
20518                    }
20519                    Ordering::Greater => {
20520                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20521                            Ordering::Less | Ordering::Equal => {
20522                                return false;
20523                            }
20524                            Ordering::Greater => break,
20525                        }
20526                    }
20527                }
20528            }
20529
20530            true
20531        });
20532        self.gutter_highlights
20533            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20534    }
20535
20536    #[cfg(feature = "test-support")]
20537    pub fn all_text_highlights(
20538        &self,
20539        window: &mut Window,
20540        cx: &mut Context<Self>,
20541    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20542        let snapshot = self.snapshot(window, cx);
20543        self.display_map.update(cx, |display_map, _| {
20544            display_map
20545                .all_text_highlights()
20546                .map(|highlight| {
20547                    let (style, ranges) = highlight.as_ref();
20548                    (
20549                        *style,
20550                        ranges
20551                            .iter()
20552                            .map(|range| range.clone().to_display_points(&snapshot))
20553                            .collect(),
20554                    )
20555                })
20556                .collect()
20557        })
20558    }
20559
20560    #[cfg(feature = "test-support")]
20561    pub fn all_text_background_highlights(
20562        &self,
20563        window: &mut Window,
20564        cx: &mut Context<Self>,
20565    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20566        let snapshot = self.snapshot(window, cx);
20567        let buffer = &snapshot.buffer_snapshot();
20568        let start = buffer.anchor_before(0);
20569        let end = buffer.anchor_after(buffer.len());
20570        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20571    }
20572
20573    #[cfg(any(test, feature = "test-support"))]
20574    pub fn sorted_background_highlights_in_range(
20575        &self,
20576        search_range: Range<Anchor>,
20577        display_snapshot: &DisplaySnapshot,
20578        theme: &Theme,
20579    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20580        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20581        res.sort_by(|a, b| {
20582            a.0.start
20583                .cmp(&b.0.start)
20584                .then_with(|| a.0.end.cmp(&b.0.end))
20585                .then_with(|| a.1.cmp(&b.1))
20586        });
20587        res
20588    }
20589
20590    #[cfg(feature = "test-support")]
20591    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20592        let snapshot = self.buffer().read(cx).snapshot(cx);
20593
20594        let highlights = self
20595            .background_highlights
20596            .get(&HighlightKey::Type(TypeId::of::<
20597                items::BufferSearchHighlights,
20598            >()));
20599
20600        if let Some((_color, ranges)) = highlights {
20601            ranges
20602                .iter()
20603                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20604                .collect_vec()
20605        } else {
20606            vec![]
20607        }
20608    }
20609
20610    fn document_highlights_for_position<'a>(
20611        &'a self,
20612        position: Anchor,
20613        buffer: &'a MultiBufferSnapshot,
20614    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20615        let read_highlights = self
20616            .background_highlights
20617            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20618            .map(|h| &h.1);
20619        let write_highlights = self
20620            .background_highlights
20621            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20622            .map(|h| &h.1);
20623        let left_position = position.bias_left(buffer);
20624        let right_position = position.bias_right(buffer);
20625        read_highlights
20626            .into_iter()
20627            .chain(write_highlights)
20628            .flat_map(move |ranges| {
20629                let start_ix = match ranges.binary_search_by(|probe| {
20630                    let cmp = probe.end.cmp(&left_position, buffer);
20631                    if cmp.is_ge() {
20632                        Ordering::Greater
20633                    } else {
20634                        Ordering::Less
20635                    }
20636                }) {
20637                    Ok(i) | Err(i) => i,
20638                };
20639
20640                ranges[start_ix..]
20641                    .iter()
20642                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20643            })
20644    }
20645
20646    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20647        self.background_highlights
20648            .get(&HighlightKey::Type(TypeId::of::<T>()))
20649            .is_some_and(|(_, highlights)| !highlights.is_empty())
20650    }
20651
20652    /// Returns all background highlights for a given range.
20653    ///
20654    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20655    pub fn background_highlights_in_range(
20656        &self,
20657        search_range: Range<Anchor>,
20658        display_snapshot: &DisplaySnapshot,
20659        theme: &Theme,
20660    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20661        let mut results = Vec::new();
20662        for (color_fetcher, ranges) in self.background_highlights.values() {
20663            let color = color_fetcher(theme);
20664            let start_ix = match ranges.binary_search_by(|probe| {
20665                let cmp = probe
20666                    .end
20667                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20668                if cmp.is_gt() {
20669                    Ordering::Greater
20670                } else {
20671                    Ordering::Less
20672                }
20673            }) {
20674                Ok(i) | Err(i) => i,
20675            };
20676            for range in &ranges[start_ix..] {
20677                if range
20678                    .start
20679                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20680                    .is_ge()
20681                {
20682                    break;
20683                }
20684
20685                let start = range.start.to_display_point(display_snapshot);
20686                let end = range.end.to_display_point(display_snapshot);
20687                results.push((start..end, color))
20688            }
20689        }
20690        results
20691    }
20692
20693    pub fn gutter_highlights_in_range(
20694        &self,
20695        search_range: Range<Anchor>,
20696        display_snapshot: &DisplaySnapshot,
20697        cx: &App,
20698    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20699        let mut results = Vec::new();
20700        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20701            let color = color_fetcher(cx);
20702            let start_ix = match ranges.binary_search_by(|probe| {
20703                let cmp = probe
20704                    .end
20705                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20706                if cmp.is_gt() {
20707                    Ordering::Greater
20708                } else {
20709                    Ordering::Less
20710                }
20711            }) {
20712                Ok(i) | Err(i) => i,
20713            };
20714            for range in &ranges[start_ix..] {
20715                if range
20716                    .start
20717                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20718                    .is_ge()
20719                {
20720                    break;
20721                }
20722
20723                let start = range.start.to_display_point(display_snapshot);
20724                let end = range.end.to_display_point(display_snapshot);
20725                results.push((start..end, color))
20726            }
20727        }
20728        results
20729    }
20730
20731    /// Get the text ranges corresponding to the redaction query
20732    pub fn redacted_ranges(
20733        &self,
20734        search_range: Range<Anchor>,
20735        display_snapshot: &DisplaySnapshot,
20736        cx: &App,
20737    ) -> Vec<Range<DisplayPoint>> {
20738        display_snapshot
20739            .buffer_snapshot()
20740            .redacted_ranges(search_range, |file| {
20741                if let Some(file) = file {
20742                    file.is_private()
20743                        && EditorSettings::get(
20744                            Some(SettingsLocation {
20745                                worktree_id: file.worktree_id(cx),
20746                                path: file.path().as_ref(),
20747                            }),
20748                            cx,
20749                        )
20750                        .redact_private_values
20751                } else {
20752                    false
20753                }
20754            })
20755            .map(|range| {
20756                range.start.to_display_point(display_snapshot)
20757                    ..range.end.to_display_point(display_snapshot)
20758            })
20759            .collect()
20760    }
20761
20762    pub fn highlight_text_key<T: 'static>(
20763        &mut self,
20764        key: usize,
20765        ranges: Vec<Range<Anchor>>,
20766        style: HighlightStyle,
20767        cx: &mut Context<Self>,
20768    ) {
20769        self.display_map.update(cx, |map, _| {
20770            map.highlight_text(
20771                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20772                ranges,
20773                style,
20774            );
20775        });
20776        cx.notify();
20777    }
20778
20779    pub fn highlight_text<T: 'static>(
20780        &mut self,
20781        ranges: Vec<Range<Anchor>>,
20782        style: HighlightStyle,
20783        cx: &mut Context<Self>,
20784    ) {
20785        self.display_map.update(cx, |map, _| {
20786            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20787        });
20788        cx.notify();
20789    }
20790
20791    pub(crate) fn highlight_inlays<T: 'static>(
20792        &mut self,
20793        highlights: Vec<InlayHighlight>,
20794        style: HighlightStyle,
20795        cx: &mut Context<Self>,
20796    ) {
20797        self.display_map.update(cx, |map, _| {
20798            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20799        });
20800        cx.notify();
20801    }
20802
20803    pub fn text_highlights<'a, T: 'static>(
20804        &'a self,
20805        cx: &'a App,
20806    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20807        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20808    }
20809
20810    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20811        let cleared = self
20812            .display_map
20813            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20814        if cleared {
20815            cx.notify();
20816        }
20817    }
20818
20819    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20820        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20821            && self.focus_handle.is_focused(window)
20822    }
20823
20824    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20825        self.show_cursor_when_unfocused = is_enabled;
20826        cx.notify();
20827    }
20828
20829    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20830        cx.notify();
20831    }
20832
20833    fn on_debug_session_event(
20834        &mut self,
20835        _session: Entity<Session>,
20836        event: &SessionEvent,
20837        cx: &mut Context<Self>,
20838    ) {
20839        if let SessionEvent::InvalidateInlineValue = event {
20840            self.refresh_inline_values(cx);
20841        }
20842    }
20843
20844    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20845        let Some(project) = self.project.clone() else {
20846            return;
20847        };
20848
20849        if !self.inline_value_cache.enabled {
20850            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20851            self.splice_inlays(&inlays, Vec::new(), cx);
20852            return;
20853        }
20854
20855        let current_execution_position = self
20856            .highlighted_rows
20857            .get(&TypeId::of::<ActiveDebugLine>())
20858            .and_then(|lines| lines.last().map(|line| line.range.end));
20859
20860        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20861            let inline_values = editor
20862                .update(cx, |editor, cx| {
20863                    let Some(current_execution_position) = current_execution_position else {
20864                        return Some(Task::ready(Ok(Vec::new())));
20865                    };
20866
20867                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20868                        let snapshot = buffer.snapshot(cx);
20869
20870                        let excerpt = snapshot.excerpt_containing(
20871                            current_execution_position..current_execution_position,
20872                        )?;
20873
20874                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20875                    })?;
20876
20877                    let range =
20878                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20879
20880                    project.inline_values(buffer, range, cx)
20881                })
20882                .ok()
20883                .flatten()?
20884                .await
20885                .context("refreshing debugger inlays")
20886                .log_err()?;
20887
20888            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20889
20890            for (buffer_id, inline_value) in inline_values
20891                .into_iter()
20892                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20893            {
20894                buffer_inline_values
20895                    .entry(buffer_id)
20896                    .or_default()
20897                    .push(inline_value);
20898            }
20899
20900            editor
20901                .update(cx, |editor, cx| {
20902                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20903                    let mut new_inlays = Vec::default();
20904
20905                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20906                        let buffer_id = buffer_snapshot.remote_id();
20907                        buffer_inline_values
20908                            .get(&buffer_id)
20909                            .into_iter()
20910                            .flatten()
20911                            .for_each(|hint| {
20912                                let inlay = Inlay::debugger(
20913                                    post_inc(&mut editor.next_inlay_id),
20914                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20915                                    hint.text(),
20916                                );
20917                                if !inlay.text().chars().contains(&'\n') {
20918                                    new_inlays.push(inlay);
20919                                }
20920                            });
20921                    }
20922
20923                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20924                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20925
20926                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20927                })
20928                .ok()?;
20929            Some(())
20930        });
20931    }
20932
20933    fn on_buffer_event(
20934        &mut self,
20935        multibuffer: &Entity<MultiBuffer>,
20936        event: &multi_buffer::Event,
20937        window: &mut Window,
20938        cx: &mut Context<Self>,
20939    ) {
20940        match event {
20941            multi_buffer::Event::Edited { edited_buffer } => {
20942                self.scrollbar_marker_state.dirty = true;
20943                self.active_indent_guides_state.dirty = true;
20944                self.refresh_active_diagnostics(cx);
20945                self.refresh_code_actions(window, cx);
20946                self.refresh_selected_text_highlights(true, window, cx);
20947                self.refresh_single_line_folds(window, cx);
20948                refresh_matching_bracket_highlights(self, cx);
20949                if self.has_active_edit_prediction() {
20950                    self.update_visible_edit_prediction(window, cx);
20951                }
20952
20953                if let Some(edited_buffer) = edited_buffer {
20954                    if edited_buffer.read(cx).file().is_none() {
20955                        cx.emit(EditorEvent::TitleChanged);
20956                    }
20957
20958                    let buffer_id = edited_buffer.read(cx).remote_id();
20959                    if let Some(project) = self.project.clone() {
20960                        self.register_buffer(buffer_id, cx);
20961                        self.update_lsp_data(Some(buffer_id), window, cx);
20962                        #[allow(clippy::mutable_key_type)]
20963                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20964                            multibuffer
20965                                .all_buffers()
20966                                .into_iter()
20967                                .filter_map(|buffer| {
20968                                    buffer.update(cx, |buffer, cx| {
20969                                        let language = buffer.language()?;
20970                                        let should_discard = project.update(cx, |project, cx| {
20971                                            project.is_local()
20972                                                && !project.has_language_servers_for(buffer, cx)
20973                                        });
20974                                        should_discard.not().then_some(language.clone())
20975                                    })
20976                                })
20977                                .collect::<HashSet<_>>()
20978                        });
20979                        if !languages_affected.is_empty() {
20980                            self.refresh_inlay_hints(
20981                                InlayHintRefreshReason::BufferEdited(languages_affected),
20982                                cx,
20983                            );
20984                        }
20985                    }
20986                }
20987
20988                cx.emit(EditorEvent::BufferEdited);
20989                cx.emit(SearchEvent::MatchesInvalidated);
20990
20991                let Some(project) = &self.project else { return };
20992                let (telemetry, is_via_ssh) = {
20993                    let project = project.read(cx);
20994                    let telemetry = project.client().telemetry().clone();
20995                    let is_via_ssh = project.is_via_remote_server();
20996                    (telemetry, is_via_ssh)
20997                };
20998                telemetry.log_edit_event("editor", is_via_ssh);
20999            }
21000            multi_buffer::Event::ExcerptsAdded {
21001                buffer,
21002                predecessor,
21003                excerpts,
21004            } => {
21005                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21006                let buffer_id = buffer.read(cx).remote_id();
21007                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21008                    && let Some(project) = &self.project
21009                {
21010                    update_uncommitted_diff_for_buffer(
21011                        cx.entity(),
21012                        project,
21013                        [buffer.clone()],
21014                        self.buffer.clone(),
21015                        cx,
21016                    )
21017                    .detach();
21018                }
21019                self.update_lsp_data(Some(buffer_id), window, cx);
21020                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21021                cx.emit(EditorEvent::ExcerptsAdded {
21022                    buffer: buffer.clone(),
21023                    predecessor: *predecessor,
21024                    excerpts: excerpts.clone(),
21025                });
21026            }
21027            multi_buffer::Event::ExcerptsRemoved {
21028                ids,
21029                removed_buffer_ids,
21030            } => {
21031                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21032                for buffer_id in removed_buffer_ids {
21033                    self.registered_buffers.remove(buffer_id);
21034                }
21035                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21036                cx.emit(EditorEvent::ExcerptsRemoved {
21037                    ids: ids.clone(),
21038                    removed_buffer_ids: removed_buffer_ids.clone(),
21039                });
21040            }
21041            multi_buffer::Event::ExcerptsEdited {
21042                excerpt_ids,
21043                buffer_ids,
21044            } => {
21045                self.display_map.update(cx, |map, cx| {
21046                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21047                });
21048                cx.emit(EditorEvent::ExcerptsEdited {
21049                    ids: excerpt_ids.clone(),
21050                });
21051            }
21052            multi_buffer::Event::ExcerptsExpanded { ids } => {
21053                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21054                self.refresh_document_highlights(cx);
21055                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21056            }
21057            multi_buffer::Event::Reparsed(buffer_id) => {
21058                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21059                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21060
21061                cx.emit(EditorEvent::Reparsed(*buffer_id));
21062            }
21063            multi_buffer::Event::DiffHunksToggled => {
21064                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21065            }
21066            multi_buffer::Event::LanguageChanged(buffer_id) => {
21067                self.registered_buffers.remove(&buffer_id);
21068                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21069                cx.emit(EditorEvent::Reparsed(*buffer_id));
21070                cx.notify();
21071            }
21072            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21073            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21074            multi_buffer::Event::FileHandleChanged
21075            | multi_buffer::Event::Reloaded
21076            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21077            multi_buffer::Event::DiagnosticsUpdated => {
21078                self.update_diagnostics_state(window, cx);
21079            }
21080            _ => {}
21081        };
21082    }
21083
21084    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21085        if !self.diagnostics_enabled() {
21086            return;
21087        }
21088        self.refresh_active_diagnostics(cx);
21089        self.refresh_inline_diagnostics(true, window, cx);
21090        self.scrollbar_marker_state.dirty = true;
21091        cx.notify();
21092    }
21093
21094    pub fn start_temporary_diff_override(&mut self) {
21095        self.load_diff_task.take();
21096        self.temporary_diff_override = true;
21097    }
21098
21099    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21100        self.temporary_diff_override = false;
21101        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21102        self.buffer.update(cx, |buffer, cx| {
21103            buffer.set_all_diff_hunks_collapsed(cx);
21104        });
21105
21106        if let Some(project) = self.project.clone() {
21107            self.load_diff_task = Some(
21108                update_uncommitted_diff_for_buffer(
21109                    cx.entity(),
21110                    &project,
21111                    self.buffer.read(cx).all_buffers(),
21112                    self.buffer.clone(),
21113                    cx,
21114                )
21115                .shared(),
21116            );
21117        }
21118    }
21119
21120    fn on_display_map_changed(
21121        &mut self,
21122        _: Entity<DisplayMap>,
21123        _: &mut Window,
21124        cx: &mut Context<Self>,
21125    ) {
21126        cx.notify();
21127    }
21128
21129    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21130        if self.diagnostics_enabled() {
21131            let new_severity = EditorSettings::get_global(cx)
21132                .diagnostics_max_severity
21133                .unwrap_or(DiagnosticSeverity::Hint);
21134            self.set_max_diagnostics_severity(new_severity, cx);
21135        }
21136        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21137        self.update_edit_prediction_settings(cx);
21138        self.refresh_edit_prediction(true, false, window, cx);
21139        self.refresh_inline_values(cx);
21140        self.refresh_inlay_hints(
21141            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21142                self.selections.newest_anchor().head(),
21143                &self.buffer.read(cx).snapshot(cx),
21144                cx,
21145            )),
21146            cx,
21147        );
21148
21149        let old_cursor_shape = self.cursor_shape;
21150        let old_show_breadcrumbs = self.show_breadcrumbs;
21151
21152        {
21153            let editor_settings = EditorSettings::get_global(cx);
21154            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21155            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21156            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21157            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21158        }
21159
21160        if old_cursor_shape != self.cursor_shape {
21161            cx.emit(EditorEvent::CursorShapeChanged);
21162        }
21163
21164        if old_show_breadcrumbs != self.show_breadcrumbs {
21165            cx.emit(EditorEvent::BreadcrumbsChanged);
21166        }
21167
21168        let project_settings = ProjectSettings::get_global(cx);
21169        self.serialize_dirty_buffers =
21170            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21171
21172        if self.mode.is_full() {
21173            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21174            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21175            if self.show_inline_diagnostics != show_inline_diagnostics {
21176                self.show_inline_diagnostics = show_inline_diagnostics;
21177                self.refresh_inline_diagnostics(false, window, cx);
21178            }
21179
21180            if self.git_blame_inline_enabled != inline_blame_enabled {
21181                self.toggle_git_blame_inline_internal(false, window, cx);
21182            }
21183
21184            let minimap_settings = EditorSettings::get_global(cx).minimap;
21185            if self.minimap_visibility != MinimapVisibility::Disabled {
21186                if self.minimap_visibility.settings_visibility()
21187                    != minimap_settings.minimap_enabled()
21188                {
21189                    self.set_minimap_visibility(
21190                        MinimapVisibility::for_mode(self.mode(), cx),
21191                        window,
21192                        cx,
21193                    );
21194                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21195                    minimap_entity.update(cx, |minimap_editor, cx| {
21196                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21197                    })
21198                }
21199            }
21200        }
21201
21202        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21203            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21204        }) {
21205            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21206                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21207            }
21208            self.refresh_colors_for_visible_range(None, window, cx);
21209        }
21210
21211        cx.notify();
21212    }
21213
21214    pub fn set_searchable(&mut self, searchable: bool) {
21215        self.searchable = searchable;
21216    }
21217
21218    pub fn searchable(&self) -> bool {
21219        self.searchable
21220    }
21221
21222    fn open_proposed_changes_editor(
21223        &mut self,
21224        _: &OpenProposedChangesEditor,
21225        window: &mut Window,
21226        cx: &mut Context<Self>,
21227    ) {
21228        let Some(workspace) = self.workspace() else {
21229            cx.propagate();
21230            return;
21231        };
21232
21233        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21234        let multi_buffer = self.buffer.read(cx);
21235        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21236        let mut new_selections_by_buffer = HashMap::default();
21237        for selection in selections {
21238            for (buffer, range, _) in
21239                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21240            {
21241                let mut range = range.to_point(buffer);
21242                range.start.column = 0;
21243                range.end.column = buffer.line_len(range.end.row);
21244                new_selections_by_buffer
21245                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21246                    .or_insert(Vec::new())
21247                    .push(range)
21248            }
21249        }
21250
21251        let proposed_changes_buffers = new_selections_by_buffer
21252            .into_iter()
21253            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21254            .collect::<Vec<_>>();
21255        let proposed_changes_editor = cx.new(|cx| {
21256            ProposedChangesEditor::new(
21257                "Proposed changes",
21258                proposed_changes_buffers,
21259                self.project.clone(),
21260                window,
21261                cx,
21262            )
21263        });
21264
21265        window.defer(cx, move |window, cx| {
21266            workspace.update(cx, |workspace, cx| {
21267                workspace.active_pane().update(cx, |pane, cx| {
21268                    pane.add_item(
21269                        Box::new(proposed_changes_editor),
21270                        true,
21271                        true,
21272                        None,
21273                        window,
21274                        cx,
21275                    );
21276                });
21277            });
21278        });
21279    }
21280
21281    pub fn open_excerpts_in_split(
21282        &mut self,
21283        _: &OpenExcerptsSplit,
21284        window: &mut Window,
21285        cx: &mut Context<Self>,
21286    ) {
21287        self.open_excerpts_common(None, true, window, cx)
21288    }
21289
21290    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21291        self.open_excerpts_common(None, false, window, cx)
21292    }
21293
21294    fn open_excerpts_common(
21295        &mut self,
21296        jump_data: Option<JumpData>,
21297        split: bool,
21298        window: &mut Window,
21299        cx: &mut Context<Self>,
21300    ) {
21301        let Some(workspace) = self.workspace() else {
21302            cx.propagate();
21303            return;
21304        };
21305
21306        if self.buffer.read(cx).is_singleton() {
21307            cx.propagate();
21308            return;
21309        }
21310
21311        let mut new_selections_by_buffer = HashMap::default();
21312        match &jump_data {
21313            Some(JumpData::MultiBufferPoint {
21314                excerpt_id,
21315                position,
21316                anchor,
21317                line_offset_from_top,
21318            }) => {
21319                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21320                if let Some(buffer) = multi_buffer_snapshot
21321                    .buffer_id_for_excerpt(*excerpt_id)
21322                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21323                {
21324                    let buffer_snapshot = buffer.read(cx).snapshot();
21325                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21326                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21327                    } else {
21328                        buffer_snapshot.clip_point(*position, Bias::Left)
21329                    };
21330                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21331                    new_selections_by_buffer.insert(
21332                        buffer,
21333                        (
21334                            vec![jump_to_offset..jump_to_offset],
21335                            Some(*line_offset_from_top),
21336                        ),
21337                    );
21338                }
21339            }
21340            Some(JumpData::MultiBufferRow {
21341                row,
21342                line_offset_from_top,
21343            }) => {
21344                let point = MultiBufferPoint::new(row.0, 0);
21345                if let Some((buffer, buffer_point, _)) =
21346                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21347                {
21348                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21349                    new_selections_by_buffer
21350                        .entry(buffer)
21351                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21352                        .0
21353                        .push(buffer_offset..buffer_offset)
21354                }
21355            }
21356            None => {
21357                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21358                let multi_buffer = self.buffer.read(cx);
21359                for selection in selections {
21360                    for (snapshot, range, _, anchor) in multi_buffer
21361                        .snapshot(cx)
21362                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21363                    {
21364                        if let Some(anchor) = anchor {
21365                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21366                            else {
21367                                continue;
21368                            };
21369                            let offset = text::ToOffset::to_offset(
21370                                &anchor.text_anchor,
21371                                &buffer_handle.read(cx).snapshot(),
21372                            );
21373                            let range = offset..offset;
21374                            new_selections_by_buffer
21375                                .entry(buffer_handle)
21376                                .or_insert((Vec::new(), None))
21377                                .0
21378                                .push(range)
21379                        } else {
21380                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21381                            else {
21382                                continue;
21383                            };
21384                            new_selections_by_buffer
21385                                .entry(buffer_handle)
21386                                .or_insert((Vec::new(), None))
21387                                .0
21388                                .push(range)
21389                        }
21390                    }
21391                }
21392            }
21393        }
21394
21395        new_selections_by_buffer
21396            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21397
21398        if new_selections_by_buffer.is_empty() {
21399            return;
21400        }
21401
21402        // We defer the pane interaction because we ourselves are a workspace item
21403        // and activating a new item causes the pane to call a method on us reentrantly,
21404        // which panics if we're on the stack.
21405        window.defer(cx, move |window, cx| {
21406            workspace.update(cx, |workspace, cx| {
21407                let pane = if split {
21408                    workspace.adjacent_pane(window, cx)
21409                } else {
21410                    workspace.active_pane().clone()
21411                };
21412
21413                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21414                    let editor = buffer
21415                        .read(cx)
21416                        .file()
21417                        .is_none()
21418                        .then(|| {
21419                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21420                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21421                            // Instead, we try to activate the existing editor in the pane first.
21422                            let (editor, pane_item_index) =
21423                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21424                                    let editor = item.downcast::<Editor>()?;
21425                                    let singleton_buffer =
21426                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21427                                    if singleton_buffer == buffer {
21428                                        Some((editor, i))
21429                                    } else {
21430                                        None
21431                                    }
21432                                })?;
21433                            pane.update(cx, |pane, cx| {
21434                                pane.activate_item(pane_item_index, true, true, window, cx)
21435                            });
21436                            Some(editor)
21437                        })
21438                        .flatten()
21439                        .unwrap_or_else(|| {
21440                            workspace.open_project_item::<Self>(
21441                                pane.clone(),
21442                                buffer,
21443                                true,
21444                                true,
21445                                window,
21446                                cx,
21447                            )
21448                        });
21449
21450                    editor.update(cx, |editor, cx| {
21451                        let autoscroll = match scroll_offset {
21452                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21453                            None => Autoscroll::newest(),
21454                        };
21455                        let nav_history = editor.nav_history.take();
21456                        editor.change_selections(
21457                            SelectionEffects::scroll(autoscroll),
21458                            window,
21459                            cx,
21460                            |s| {
21461                                s.select_ranges(ranges);
21462                            },
21463                        );
21464                        editor.nav_history = nav_history;
21465                    });
21466                }
21467            })
21468        });
21469    }
21470
21471    // For now, don't allow opening excerpts in buffers that aren't backed by
21472    // regular project files.
21473    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21474        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21475    }
21476
21477    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21478        let snapshot = self.buffer.read(cx).read(cx);
21479        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21480        Some(
21481            ranges
21482                .iter()
21483                .map(move |range| {
21484                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21485                })
21486                .collect(),
21487        )
21488    }
21489
21490    fn selection_replacement_ranges(
21491        &self,
21492        range: Range<OffsetUtf16>,
21493        cx: &mut App,
21494    ) -> Vec<Range<OffsetUtf16>> {
21495        let selections = self
21496            .selections
21497            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21498        let newest_selection = selections
21499            .iter()
21500            .max_by_key(|selection| selection.id)
21501            .unwrap();
21502        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21503        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21504        let snapshot = self.buffer.read(cx).read(cx);
21505        selections
21506            .into_iter()
21507            .map(|mut selection| {
21508                selection.start.0 =
21509                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21510                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21511                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21512                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21513            })
21514            .collect()
21515    }
21516
21517    fn report_editor_event(
21518        &self,
21519        reported_event: ReportEditorEvent,
21520        file_extension: Option<String>,
21521        cx: &App,
21522    ) {
21523        if cfg!(any(test, feature = "test-support")) {
21524            return;
21525        }
21526
21527        let Some(project) = &self.project else { return };
21528
21529        // If None, we are in a file without an extension
21530        let file = self
21531            .buffer
21532            .read(cx)
21533            .as_singleton()
21534            .and_then(|b| b.read(cx).file());
21535        let file_extension = file_extension.or(file
21536            .as_ref()
21537            .and_then(|file| Path::new(file.file_name(cx)).extension())
21538            .and_then(|e| e.to_str())
21539            .map(|a| a.to_string()));
21540
21541        let vim_mode = vim_enabled(cx);
21542
21543        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21544        let copilot_enabled = edit_predictions_provider
21545            == language::language_settings::EditPredictionProvider::Copilot;
21546        let copilot_enabled_for_language = self
21547            .buffer
21548            .read(cx)
21549            .language_settings(cx)
21550            .show_edit_predictions;
21551
21552        let project = project.read(cx);
21553        let event_type = reported_event.event_type();
21554
21555        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21556            telemetry::event!(
21557                event_type,
21558                type = if auto_saved {"autosave"} else {"manual"},
21559                file_extension,
21560                vim_mode,
21561                copilot_enabled,
21562                copilot_enabled_for_language,
21563                edit_predictions_provider,
21564                is_via_ssh = project.is_via_remote_server(),
21565            );
21566        } else {
21567            telemetry::event!(
21568                event_type,
21569                file_extension,
21570                vim_mode,
21571                copilot_enabled,
21572                copilot_enabled_for_language,
21573                edit_predictions_provider,
21574                is_via_ssh = project.is_via_remote_server(),
21575            );
21576        };
21577    }
21578
21579    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21580    /// with each line being an array of {text, highlight} objects.
21581    fn copy_highlight_json(
21582        &mut self,
21583        _: &CopyHighlightJson,
21584        window: &mut Window,
21585        cx: &mut Context<Self>,
21586    ) {
21587        #[derive(Serialize)]
21588        struct Chunk<'a> {
21589            text: String,
21590            highlight: Option<&'a str>,
21591        }
21592
21593        let snapshot = self.buffer.read(cx).snapshot(cx);
21594        let range = self
21595            .selected_text_range(false, window, cx)
21596            .and_then(|selection| {
21597                if selection.range.is_empty() {
21598                    None
21599                } else {
21600                    Some(selection.range)
21601                }
21602            })
21603            .unwrap_or_else(|| 0..snapshot.len());
21604
21605        let chunks = snapshot.chunks(range, true);
21606        let mut lines = Vec::new();
21607        let mut line: VecDeque<Chunk> = VecDeque::new();
21608
21609        let Some(style) = self.style.as_ref() else {
21610            return;
21611        };
21612
21613        for chunk in chunks {
21614            let highlight = chunk
21615                .syntax_highlight_id
21616                .and_then(|id| id.name(&style.syntax));
21617            let mut chunk_lines = chunk.text.split('\n').peekable();
21618            while let Some(text) = chunk_lines.next() {
21619                let mut merged_with_last_token = false;
21620                if let Some(last_token) = line.back_mut()
21621                    && last_token.highlight == highlight
21622                {
21623                    last_token.text.push_str(text);
21624                    merged_with_last_token = true;
21625                }
21626
21627                if !merged_with_last_token {
21628                    line.push_back(Chunk {
21629                        text: text.into(),
21630                        highlight,
21631                    });
21632                }
21633
21634                if chunk_lines.peek().is_some() {
21635                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21636                        line.pop_front();
21637                    }
21638                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21639                        line.pop_back();
21640                    }
21641
21642                    lines.push(mem::take(&mut line));
21643                }
21644            }
21645        }
21646
21647        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21648            return;
21649        };
21650        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21651    }
21652
21653    pub fn open_context_menu(
21654        &mut self,
21655        _: &OpenContextMenu,
21656        window: &mut Window,
21657        cx: &mut Context<Self>,
21658    ) {
21659        self.request_autoscroll(Autoscroll::newest(), cx);
21660        let position = self
21661            .selections
21662            .newest_display(&self.display_snapshot(cx))
21663            .start;
21664        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21665    }
21666
21667    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21668        &self.inlay_hint_cache
21669    }
21670
21671    pub fn replay_insert_event(
21672        &mut self,
21673        text: &str,
21674        relative_utf16_range: Option<Range<isize>>,
21675        window: &mut Window,
21676        cx: &mut Context<Self>,
21677    ) {
21678        if !self.input_enabled {
21679            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21680            return;
21681        }
21682        if let Some(relative_utf16_range) = relative_utf16_range {
21683            let selections = self
21684                .selections
21685                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21686            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21687                let new_ranges = selections.into_iter().map(|range| {
21688                    let start = OffsetUtf16(
21689                        range
21690                            .head()
21691                            .0
21692                            .saturating_add_signed(relative_utf16_range.start),
21693                    );
21694                    let end = OffsetUtf16(
21695                        range
21696                            .head()
21697                            .0
21698                            .saturating_add_signed(relative_utf16_range.end),
21699                    );
21700                    start..end
21701                });
21702                s.select_ranges(new_ranges);
21703            });
21704        }
21705
21706        self.handle_input(text, window, cx);
21707    }
21708
21709    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21710        let Some(provider) = self.semantics_provider.as_ref() else {
21711            return false;
21712        };
21713
21714        let mut supports = false;
21715        self.buffer().update(cx, |this, cx| {
21716            this.for_each_buffer(|buffer| {
21717                supports |= provider.supports_inlay_hints(buffer, cx);
21718            });
21719        });
21720
21721        supports
21722    }
21723
21724    pub fn is_focused(&self, window: &Window) -> bool {
21725        self.focus_handle.is_focused(window)
21726    }
21727
21728    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21729        cx.emit(EditorEvent::Focused);
21730
21731        if let Some(descendant) = self
21732            .last_focused_descendant
21733            .take()
21734            .and_then(|descendant| descendant.upgrade())
21735        {
21736            window.focus(&descendant);
21737        } else {
21738            if let Some(blame) = self.blame.as_ref() {
21739                blame.update(cx, GitBlame::focus)
21740            }
21741
21742            self.blink_manager.update(cx, BlinkManager::enable);
21743            self.show_cursor_names(window, cx);
21744            self.buffer.update(cx, |buffer, cx| {
21745                buffer.finalize_last_transaction(cx);
21746                if self.leader_id.is_none() {
21747                    buffer.set_active_selections(
21748                        &self.selections.disjoint_anchors_arc(),
21749                        self.selections.line_mode(),
21750                        self.cursor_shape,
21751                        cx,
21752                    );
21753                }
21754            });
21755        }
21756    }
21757
21758    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21759        cx.emit(EditorEvent::FocusedIn)
21760    }
21761
21762    fn handle_focus_out(
21763        &mut self,
21764        event: FocusOutEvent,
21765        _window: &mut Window,
21766        cx: &mut Context<Self>,
21767    ) {
21768        if event.blurred != self.focus_handle {
21769            self.last_focused_descendant = Some(event.blurred);
21770        }
21771        self.selection_drag_state = SelectionDragState::None;
21772        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21773    }
21774
21775    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21776        self.blink_manager.update(cx, BlinkManager::disable);
21777        self.buffer
21778            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21779
21780        if let Some(blame) = self.blame.as_ref() {
21781            blame.update(cx, GitBlame::blur)
21782        }
21783        if !self.hover_state.focused(window, cx) {
21784            hide_hover(self, cx);
21785        }
21786        if !self
21787            .context_menu
21788            .borrow()
21789            .as_ref()
21790            .is_some_and(|context_menu| context_menu.focused(window, cx))
21791        {
21792            self.hide_context_menu(window, cx);
21793        }
21794        self.take_active_edit_prediction(cx);
21795        cx.emit(EditorEvent::Blurred);
21796        cx.notify();
21797    }
21798
21799    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21800        let mut pending: String = window
21801            .pending_input_keystrokes()
21802            .into_iter()
21803            .flatten()
21804            .filter_map(|keystroke| {
21805                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21806                    keystroke.key_char.clone()
21807                } else {
21808                    None
21809                }
21810            })
21811            .collect();
21812
21813        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21814            pending = "".to_string();
21815        }
21816
21817        let existing_pending = self
21818            .text_highlights::<PendingInput>(cx)
21819            .map(|(_, ranges)| ranges.to_vec());
21820        if existing_pending.is_none() && pending.is_empty() {
21821            return;
21822        }
21823        let transaction =
21824            self.transact(window, cx, |this, window, cx| {
21825                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21826                let edits = selections
21827                    .iter()
21828                    .map(|selection| (selection.end..selection.end, pending.clone()));
21829                this.edit(edits, cx);
21830                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21831                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21832                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21833                    }));
21834                });
21835                if let Some(existing_ranges) = existing_pending {
21836                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21837                    this.edit(edits, cx);
21838                }
21839            });
21840
21841        let snapshot = self.snapshot(window, cx);
21842        let ranges = self
21843            .selections
21844            .all::<usize>(&snapshot.display_snapshot)
21845            .into_iter()
21846            .map(|selection| {
21847                snapshot.buffer_snapshot().anchor_after(selection.end)
21848                    ..snapshot
21849                        .buffer_snapshot()
21850                        .anchor_before(selection.end + pending.len())
21851            })
21852            .collect();
21853
21854        if pending.is_empty() {
21855            self.clear_highlights::<PendingInput>(cx);
21856        } else {
21857            self.highlight_text::<PendingInput>(
21858                ranges,
21859                HighlightStyle {
21860                    underline: Some(UnderlineStyle {
21861                        thickness: px(1.),
21862                        color: None,
21863                        wavy: false,
21864                    }),
21865                    ..Default::default()
21866                },
21867                cx,
21868            );
21869        }
21870
21871        self.ime_transaction = self.ime_transaction.or(transaction);
21872        if let Some(transaction) = self.ime_transaction {
21873            self.buffer.update(cx, |buffer, cx| {
21874                buffer.group_until_transaction(transaction, cx);
21875            });
21876        }
21877
21878        if self.text_highlights::<PendingInput>(cx).is_none() {
21879            self.ime_transaction.take();
21880        }
21881    }
21882
21883    pub fn register_action_renderer(
21884        &mut self,
21885        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21886    ) -> Subscription {
21887        let id = self.next_editor_action_id.post_inc();
21888        self.editor_actions
21889            .borrow_mut()
21890            .insert(id, Box::new(listener));
21891
21892        let editor_actions = self.editor_actions.clone();
21893        Subscription::new(move || {
21894            editor_actions.borrow_mut().remove(&id);
21895        })
21896    }
21897
21898    pub fn register_action<A: Action>(
21899        &mut self,
21900        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21901    ) -> Subscription {
21902        let id = self.next_editor_action_id.post_inc();
21903        let listener = Arc::new(listener);
21904        self.editor_actions.borrow_mut().insert(
21905            id,
21906            Box::new(move |_, window, _| {
21907                let listener = listener.clone();
21908                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21909                    let action = action.downcast_ref().unwrap();
21910                    if phase == DispatchPhase::Bubble {
21911                        listener(action, window, cx)
21912                    }
21913                })
21914            }),
21915        );
21916
21917        let editor_actions = self.editor_actions.clone();
21918        Subscription::new(move || {
21919            editor_actions.borrow_mut().remove(&id);
21920        })
21921    }
21922
21923    pub fn file_header_size(&self) -> u32 {
21924        FILE_HEADER_HEIGHT
21925    }
21926
21927    pub fn restore(
21928        &mut self,
21929        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21930        window: &mut Window,
21931        cx: &mut Context<Self>,
21932    ) {
21933        let workspace = self.workspace();
21934        let project = self.project();
21935        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21936            let mut tasks = Vec::new();
21937            for (buffer_id, changes) in revert_changes {
21938                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21939                    buffer.update(cx, |buffer, cx| {
21940                        buffer.edit(
21941                            changes
21942                                .into_iter()
21943                                .map(|(range, text)| (range, text.to_string())),
21944                            None,
21945                            cx,
21946                        );
21947                    });
21948
21949                    if let Some(project) =
21950                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21951                    {
21952                        project.update(cx, |project, cx| {
21953                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21954                        })
21955                    }
21956                }
21957            }
21958            tasks
21959        });
21960        cx.spawn_in(window, async move |_, cx| {
21961            for (buffer, task) in save_tasks {
21962                let result = task.await;
21963                if result.is_err() {
21964                    let Some(path) = buffer
21965                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21966                        .ok()
21967                    else {
21968                        continue;
21969                    };
21970                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21971                        let Some(task) = cx
21972                            .update_window_entity(workspace, |workspace, window, cx| {
21973                                workspace
21974                                    .open_path_preview(path, None, false, false, false, window, cx)
21975                            })
21976                            .ok()
21977                        else {
21978                            continue;
21979                        };
21980                        task.await.log_err();
21981                    }
21982                }
21983            }
21984        })
21985        .detach();
21986        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21987            selections.refresh()
21988        });
21989    }
21990
21991    pub fn to_pixel_point(
21992        &self,
21993        source: multi_buffer::Anchor,
21994        editor_snapshot: &EditorSnapshot,
21995        window: &mut Window,
21996    ) -> Option<gpui::Point<Pixels>> {
21997        let source_point = source.to_display_point(editor_snapshot);
21998        self.display_to_pixel_point(source_point, editor_snapshot, window)
21999    }
22000
22001    pub fn display_to_pixel_point(
22002        &self,
22003        source: DisplayPoint,
22004        editor_snapshot: &EditorSnapshot,
22005        window: &mut Window,
22006    ) -> Option<gpui::Point<Pixels>> {
22007        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22008        let text_layout_details = self.text_layout_details(window);
22009        let scroll_top = text_layout_details
22010            .scroll_anchor
22011            .scroll_position(editor_snapshot)
22012            .y;
22013
22014        if source.row().as_f64() < scroll_top.floor() {
22015            return None;
22016        }
22017        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22018        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22019        Some(gpui::Point::new(source_x, source_y))
22020    }
22021
22022    pub fn has_visible_completions_menu(&self) -> bool {
22023        !self.edit_prediction_preview_is_active()
22024            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22025                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22026            })
22027    }
22028
22029    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22030        if self.mode.is_minimap() {
22031            return;
22032        }
22033        self.addons
22034            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22035    }
22036
22037    pub fn unregister_addon<T: Addon>(&mut self) {
22038        self.addons.remove(&std::any::TypeId::of::<T>());
22039    }
22040
22041    pub fn addon<T: Addon>(&self) -> Option<&T> {
22042        let type_id = std::any::TypeId::of::<T>();
22043        self.addons
22044            .get(&type_id)
22045            .and_then(|item| item.to_any().downcast_ref::<T>())
22046    }
22047
22048    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22049        let type_id = std::any::TypeId::of::<T>();
22050        self.addons
22051            .get_mut(&type_id)
22052            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22053    }
22054
22055    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22056        let text_layout_details = self.text_layout_details(window);
22057        let style = &text_layout_details.editor_style;
22058        let font_id = window.text_system().resolve_font(&style.text.font());
22059        let font_size = style.text.font_size.to_pixels(window.rem_size());
22060        let line_height = style.text.line_height_in_pixels(window.rem_size());
22061        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22062        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22063
22064        CharacterDimensions {
22065            em_width,
22066            em_advance,
22067            line_height,
22068        }
22069    }
22070
22071    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22072        self.load_diff_task.clone()
22073    }
22074
22075    fn read_metadata_from_db(
22076        &mut self,
22077        item_id: u64,
22078        workspace_id: WorkspaceId,
22079        window: &mut Window,
22080        cx: &mut Context<Editor>,
22081    ) {
22082        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22083            && !self.mode.is_minimap()
22084            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22085        {
22086            let buffer_snapshot = OnceCell::new();
22087
22088            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22089                && !folds.is_empty()
22090            {
22091                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22092                self.fold_ranges(
22093                    folds
22094                        .into_iter()
22095                        .map(|(start, end)| {
22096                            snapshot.clip_offset(start, Bias::Left)
22097                                ..snapshot.clip_offset(end, Bias::Right)
22098                        })
22099                        .collect(),
22100                    false,
22101                    window,
22102                    cx,
22103                );
22104            }
22105
22106            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22107                && !selections.is_empty()
22108            {
22109                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22110                // skip adding the initial selection to selection history
22111                self.selection_history.mode = SelectionHistoryMode::Skipping;
22112                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22113                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22114                        snapshot.clip_offset(start, Bias::Left)
22115                            ..snapshot.clip_offset(end, Bias::Right)
22116                    }));
22117                });
22118                self.selection_history.mode = SelectionHistoryMode::Normal;
22119            };
22120        }
22121
22122        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22123    }
22124
22125    fn update_lsp_data(
22126        &mut self,
22127        for_buffer: Option<BufferId>,
22128        window: &mut Window,
22129        cx: &mut Context<'_, Self>,
22130    ) {
22131        self.pull_diagnostics(for_buffer, window, cx);
22132        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22133    }
22134
22135    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22136        if self.ignore_lsp_data() {
22137            return;
22138        }
22139        for (_, (visible_buffer, _, _)) in self.visible_excerpts(None, cx) {
22140            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22141        }
22142    }
22143
22144    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) -> bool {
22145        if !self.registered_buffers.contains_key(&buffer_id)
22146            && let Some(project) = self.project.as_ref()
22147        {
22148            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22149                project.update(cx, |project, cx| {
22150                    self.registered_buffers.insert(
22151                        buffer_id,
22152                        project.register_buffer_with_language_servers(&buffer, cx),
22153                    );
22154                });
22155                return true;
22156            } else {
22157                self.registered_buffers.remove(&buffer_id);
22158            }
22159        }
22160
22161        false
22162    }
22163
22164    fn ignore_lsp_data(&self) -> bool {
22165        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22166        // skip any LSP updates for it.
22167        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22168    }
22169}
22170
22171fn edit_for_markdown_paste<'a>(
22172    buffer: &MultiBufferSnapshot,
22173    range: Range<usize>,
22174    to_insert: &'a str,
22175    url: Option<url::Url>,
22176) -> (Range<usize>, Cow<'a, str>) {
22177    if url.is_none() {
22178        return (range, Cow::Borrowed(to_insert));
22179    };
22180
22181    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22182
22183    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22184        Cow::Borrowed(to_insert)
22185    } else {
22186        Cow::Owned(format!("[{old_text}]({to_insert})"))
22187    };
22188    (range, new_text)
22189}
22190
22191fn vim_enabled(cx: &App) -> bool {
22192    vim_mode_setting::VimModeSetting::try_get(cx)
22193        .map(|vim_mode| vim_mode.0)
22194        .unwrap_or(false)
22195}
22196
22197fn process_completion_for_edit(
22198    completion: &Completion,
22199    intent: CompletionIntent,
22200    buffer: &Entity<Buffer>,
22201    cursor_position: &text::Anchor,
22202    cx: &mut Context<Editor>,
22203) -> CompletionEdit {
22204    let buffer = buffer.read(cx);
22205    let buffer_snapshot = buffer.snapshot();
22206    let (snippet, new_text) = if completion.is_snippet() {
22207        let mut snippet_source = completion.new_text.clone();
22208        // Workaround for typescript language server issues so that methods don't expand within
22209        // strings and functions with type expressions. The previous point is used because the query
22210        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22211        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22212        let previous_point = if previous_point.column > 0 {
22213            cursor_position.to_previous_offset(&buffer_snapshot)
22214        } else {
22215            cursor_position.to_offset(&buffer_snapshot)
22216        };
22217        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22218            && scope.prefers_label_for_snippet_in_completion()
22219            && let Some(label) = completion.label()
22220            && matches!(
22221                completion.kind(),
22222                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22223            )
22224        {
22225            snippet_source = label;
22226        }
22227        match Snippet::parse(&snippet_source).log_err() {
22228            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22229            None => (None, completion.new_text.clone()),
22230        }
22231    } else {
22232        (None, completion.new_text.clone())
22233    };
22234
22235    let mut range_to_replace = {
22236        let replace_range = &completion.replace_range;
22237        if let CompletionSource::Lsp {
22238            insert_range: Some(insert_range),
22239            ..
22240        } = &completion.source
22241        {
22242            debug_assert_eq!(
22243                insert_range.start, replace_range.start,
22244                "insert_range and replace_range should start at the same position"
22245            );
22246            debug_assert!(
22247                insert_range
22248                    .start
22249                    .cmp(cursor_position, &buffer_snapshot)
22250                    .is_le(),
22251                "insert_range should start before or at cursor position"
22252            );
22253            debug_assert!(
22254                replace_range
22255                    .start
22256                    .cmp(cursor_position, &buffer_snapshot)
22257                    .is_le(),
22258                "replace_range should start before or at cursor position"
22259            );
22260
22261            let should_replace = match intent {
22262                CompletionIntent::CompleteWithInsert => false,
22263                CompletionIntent::CompleteWithReplace => true,
22264                CompletionIntent::Complete | CompletionIntent::Compose => {
22265                    let insert_mode =
22266                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22267                            .completions
22268                            .lsp_insert_mode;
22269                    match insert_mode {
22270                        LspInsertMode::Insert => false,
22271                        LspInsertMode::Replace => true,
22272                        LspInsertMode::ReplaceSubsequence => {
22273                            let mut text_to_replace = buffer.chars_for_range(
22274                                buffer.anchor_before(replace_range.start)
22275                                    ..buffer.anchor_after(replace_range.end),
22276                            );
22277                            let mut current_needle = text_to_replace.next();
22278                            for haystack_ch in completion.label.text.chars() {
22279                                if let Some(needle_ch) = current_needle
22280                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22281                                {
22282                                    current_needle = text_to_replace.next();
22283                                }
22284                            }
22285                            current_needle.is_none()
22286                        }
22287                        LspInsertMode::ReplaceSuffix => {
22288                            if replace_range
22289                                .end
22290                                .cmp(cursor_position, &buffer_snapshot)
22291                                .is_gt()
22292                            {
22293                                let range_after_cursor = *cursor_position..replace_range.end;
22294                                let text_after_cursor = buffer
22295                                    .text_for_range(
22296                                        buffer.anchor_before(range_after_cursor.start)
22297                                            ..buffer.anchor_after(range_after_cursor.end),
22298                                    )
22299                                    .collect::<String>()
22300                                    .to_ascii_lowercase();
22301                                completion
22302                                    .label
22303                                    .text
22304                                    .to_ascii_lowercase()
22305                                    .ends_with(&text_after_cursor)
22306                            } else {
22307                                true
22308                            }
22309                        }
22310                    }
22311                }
22312            };
22313
22314            if should_replace {
22315                replace_range.clone()
22316            } else {
22317                insert_range.clone()
22318            }
22319        } else {
22320            replace_range.clone()
22321        }
22322    };
22323
22324    if range_to_replace
22325        .end
22326        .cmp(cursor_position, &buffer_snapshot)
22327        .is_lt()
22328    {
22329        range_to_replace.end = *cursor_position;
22330    }
22331
22332    CompletionEdit {
22333        new_text,
22334        replace_range: range_to_replace.to_offset(buffer),
22335        snippet,
22336    }
22337}
22338
22339struct CompletionEdit {
22340    new_text: String,
22341    replace_range: Range<usize>,
22342    snippet: Option<Snippet>,
22343}
22344
22345fn insert_extra_newline_brackets(
22346    buffer: &MultiBufferSnapshot,
22347    range: Range<usize>,
22348    language: &language::LanguageScope,
22349) -> bool {
22350    let leading_whitespace_len = buffer
22351        .reversed_chars_at(range.start)
22352        .take_while(|c| c.is_whitespace() && *c != '\n')
22353        .map(|c| c.len_utf8())
22354        .sum::<usize>();
22355    let trailing_whitespace_len = buffer
22356        .chars_at(range.end)
22357        .take_while(|c| c.is_whitespace() && *c != '\n')
22358        .map(|c| c.len_utf8())
22359        .sum::<usize>();
22360    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22361
22362    language.brackets().any(|(pair, enabled)| {
22363        let pair_start = pair.start.trim_end();
22364        let pair_end = pair.end.trim_start();
22365
22366        enabled
22367            && pair.newline
22368            && buffer.contains_str_at(range.end, pair_end)
22369            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22370    })
22371}
22372
22373fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22374    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22375        [(buffer, range, _)] => (*buffer, range.clone()),
22376        _ => return false,
22377    };
22378    let pair = {
22379        let mut result: Option<BracketMatch> = None;
22380
22381        for pair in buffer
22382            .all_bracket_ranges(range.clone())
22383            .filter(move |pair| {
22384                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22385            })
22386        {
22387            let len = pair.close_range.end - pair.open_range.start;
22388
22389            if let Some(existing) = &result {
22390                let existing_len = existing.close_range.end - existing.open_range.start;
22391                if len > existing_len {
22392                    continue;
22393                }
22394            }
22395
22396            result = Some(pair);
22397        }
22398
22399        result
22400    };
22401    let Some(pair) = pair else {
22402        return false;
22403    };
22404    pair.newline_only
22405        && buffer
22406            .chars_for_range(pair.open_range.end..range.start)
22407            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22408            .all(|c| c.is_whitespace() && c != '\n')
22409}
22410
22411fn update_uncommitted_diff_for_buffer(
22412    editor: Entity<Editor>,
22413    project: &Entity<Project>,
22414    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22415    buffer: Entity<MultiBuffer>,
22416    cx: &mut App,
22417) -> Task<()> {
22418    let mut tasks = Vec::new();
22419    project.update(cx, |project, cx| {
22420        for buffer in buffers {
22421            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22422                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22423            }
22424        }
22425    });
22426    cx.spawn(async move |cx| {
22427        let diffs = future::join_all(tasks).await;
22428        if editor
22429            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22430            .unwrap_or(false)
22431        {
22432            return;
22433        }
22434
22435        buffer
22436            .update(cx, |buffer, cx| {
22437                for diff in diffs.into_iter().flatten() {
22438                    buffer.add_diff(diff, cx);
22439                }
22440            })
22441            .ok();
22442    })
22443}
22444
22445fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22446    let tab_size = tab_size.get() as usize;
22447    let mut width = offset;
22448
22449    for ch in text.chars() {
22450        width += if ch == '\t' {
22451            tab_size - (width % tab_size)
22452        } else {
22453            1
22454        };
22455    }
22456
22457    width - offset
22458}
22459
22460#[cfg(test)]
22461mod tests {
22462    use super::*;
22463
22464    #[test]
22465    fn test_string_size_with_expanded_tabs() {
22466        let nz = |val| NonZeroU32::new(val).unwrap();
22467        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22468        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22469        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22470        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22471        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22472        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22473        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22474        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22475    }
22476}
22477
22478/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22479struct WordBreakingTokenizer<'a> {
22480    input: &'a str,
22481}
22482
22483impl<'a> WordBreakingTokenizer<'a> {
22484    fn new(input: &'a str) -> Self {
22485        Self { input }
22486    }
22487}
22488
22489fn is_char_ideographic(ch: char) -> bool {
22490    use unicode_script::Script::*;
22491    use unicode_script::UnicodeScript;
22492    matches!(ch.script(), Han | Tangut | Yi)
22493}
22494
22495fn is_grapheme_ideographic(text: &str) -> bool {
22496    text.chars().any(is_char_ideographic)
22497}
22498
22499fn is_grapheme_whitespace(text: &str) -> bool {
22500    text.chars().any(|x| x.is_whitespace())
22501}
22502
22503fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22504    text.chars()
22505        .next()
22506        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22507}
22508
22509#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22510enum WordBreakToken<'a> {
22511    Word { token: &'a str, grapheme_len: usize },
22512    InlineWhitespace { token: &'a str, grapheme_len: usize },
22513    Newline,
22514}
22515
22516impl<'a> Iterator for WordBreakingTokenizer<'a> {
22517    /// Yields a span, the count of graphemes in the token, and whether it was
22518    /// whitespace. Note that it also breaks at word boundaries.
22519    type Item = WordBreakToken<'a>;
22520
22521    fn next(&mut self) -> Option<Self::Item> {
22522        use unicode_segmentation::UnicodeSegmentation;
22523        if self.input.is_empty() {
22524            return None;
22525        }
22526
22527        let mut iter = self.input.graphemes(true).peekable();
22528        let mut offset = 0;
22529        let mut grapheme_len = 0;
22530        if let Some(first_grapheme) = iter.next() {
22531            let is_newline = first_grapheme == "\n";
22532            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22533            offset += first_grapheme.len();
22534            grapheme_len += 1;
22535            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22536                if let Some(grapheme) = iter.peek().copied()
22537                    && should_stay_with_preceding_ideograph(grapheme)
22538                {
22539                    offset += grapheme.len();
22540                    grapheme_len += 1;
22541                }
22542            } else {
22543                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22544                let mut next_word_bound = words.peek().copied();
22545                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22546                    next_word_bound = words.next();
22547                }
22548                while let Some(grapheme) = iter.peek().copied() {
22549                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22550                        break;
22551                    };
22552                    if is_grapheme_whitespace(grapheme) != is_whitespace
22553                        || (grapheme == "\n") != is_newline
22554                    {
22555                        break;
22556                    };
22557                    offset += grapheme.len();
22558                    grapheme_len += 1;
22559                    iter.next();
22560                }
22561            }
22562            let token = &self.input[..offset];
22563            self.input = &self.input[offset..];
22564            if token == "\n" {
22565                Some(WordBreakToken::Newline)
22566            } else if is_whitespace {
22567                Some(WordBreakToken::InlineWhitespace {
22568                    token,
22569                    grapheme_len,
22570                })
22571            } else {
22572                Some(WordBreakToken::Word {
22573                    token,
22574                    grapheme_len,
22575                })
22576            }
22577        } else {
22578            None
22579        }
22580    }
22581}
22582
22583#[test]
22584fn test_word_breaking_tokenizer() {
22585    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22586        ("", &[]),
22587        ("  ", &[whitespace("  ", 2)]),
22588        ("Ʒ", &[word("Ʒ", 1)]),
22589        ("Ǽ", &[word("Ǽ", 1)]),
22590        ("", &[word("", 1)]),
22591        ("⋑⋑", &[word("⋑⋑", 2)]),
22592        (
22593            "原理,进而",
22594            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22595        ),
22596        (
22597            "hello world",
22598            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22599        ),
22600        (
22601            "hello, world",
22602            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22603        ),
22604        (
22605            "  hello world",
22606            &[
22607                whitespace("  ", 2),
22608                word("hello", 5),
22609                whitespace(" ", 1),
22610                word("world", 5),
22611            ],
22612        ),
22613        (
22614            "这是什么 \n 钢笔",
22615            &[
22616                word("", 1),
22617                word("", 1),
22618                word("", 1),
22619                word("", 1),
22620                whitespace(" ", 1),
22621                newline(),
22622                whitespace(" ", 1),
22623                word("", 1),
22624                word("", 1),
22625            ],
22626        ),
22627        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22628    ];
22629
22630    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22631        WordBreakToken::Word {
22632            token,
22633            grapheme_len,
22634        }
22635    }
22636
22637    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22638        WordBreakToken::InlineWhitespace {
22639            token,
22640            grapheme_len,
22641        }
22642    }
22643
22644    fn newline() -> WordBreakToken<'static> {
22645        WordBreakToken::Newline
22646    }
22647
22648    for (input, result) in tests {
22649        assert_eq!(
22650            WordBreakingTokenizer::new(input)
22651                .collect::<Vec<_>>()
22652                .as_slice(),
22653            *result,
22654        );
22655    }
22656}
22657
22658fn wrap_with_prefix(
22659    first_line_prefix: String,
22660    subsequent_lines_prefix: String,
22661    unwrapped_text: String,
22662    wrap_column: usize,
22663    tab_size: NonZeroU32,
22664    preserve_existing_whitespace: bool,
22665) -> String {
22666    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22667    let subsequent_lines_prefix_len =
22668        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22669    let mut wrapped_text = String::new();
22670    let mut current_line = first_line_prefix;
22671    let mut is_first_line = true;
22672
22673    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22674    let mut current_line_len = first_line_prefix_len;
22675    let mut in_whitespace = false;
22676    for token in tokenizer {
22677        let have_preceding_whitespace = in_whitespace;
22678        match token {
22679            WordBreakToken::Word {
22680                token,
22681                grapheme_len,
22682            } => {
22683                in_whitespace = false;
22684                let current_prefix_len = if is_first_line {
22685                    first_line_prefix_len
22686                } else {
22687                    subsequent_lines_prefix_len
22688                };
22689                if current_line_len + grapheme_len > wrap_column
22690                    && current_line_len != current_prefix_len
22691                {
22692                    wrapped_text.push_str(current_line.trim_end());
22693                    wrapped_text.push('\n');
22694                    is_first_line = false;
22695                    current_line = subsequent_lines_prefix.clone();
22696                    current_line_len = subsequent_lines_prefix_len;
22697                }
22698                current_line.push_str(token);
22699                current_line_len += grapheme_len;
22700            }
22701            WordBreakToken::InlineWhitespace {
22702                mut token,
22703                mut grapheme_len,
22704            } => {
22705                in_whitespace = true;
22706                if have_preceding_whitespace && !preserve_existing_whitespace {
22707                    continue;
22708                }
22709                if !preserve_existing_whitespace {
22710                    // Keep a single whitespace grapheme as-is
22711                    if let Some(first) =
22712                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22713                    {
22714                        token = first;
22715                    } else {
22716                        token = " ";
22717                    }
22718                    grapheme_len = 1;
22719                }
22720                let current_prefix_len = if is_first_line {
22721                    first_line_prefix_len
22722                } else {
22723                    subsequent_lines_prefix_len
22724                };
22725                if current_line_len + grapheme_len > wrap_column {
22726                    wrapped_text.push_str(current_line.trim_end());
22727                    wrapped_text.push('\n');
22728                    is_first_line = false;
22729                    current_line = subsequent_lines_prefix.clone();
22730                    current_line_len = subsequent_lines_prefix_len;
22731                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22732                    current_line.push_str(token);
22733                    current_line_len += grapheme_len;
22734                }
22735            }
22736            WordBreakToken::Newline => {
22737                in_whitespace = true;
22738                let current_prefix_len = if is_first_line {
22739                    first_line_prefix_len
22740                } else {
22741                    subsequent_lines_prefix_len
22742                };
22743                if preserve_existing_whitespace {
22744                    wrapped_text.push_str(current_line.trim_end());
22745                    wrapped_text.push('\n');
22746                    is_first_line = false;
22747                    current_line = subsequent_lines_prefix.clone();
22748                    current_line_len = subsequent_lines_prefix_len;
22749                } else if have_preceding_whitespace {
22750                    continue;
22751                } else if current_line_len + 1 > wrap_column
22752                    && current_line_len != current_prefix_len
22753                {
22754                    wrapped_text.push_str(current_line.trim_end());
22755                    wrapped_text.push('\n');
22756                    is_first_line = false;
22757                    current_line = subsequent_lines_prefix.clone();
22758                    current_line_len = subsequent_lines_prefix_len;
22759                } else if current_line_len != current_prefix_len {
22760                    current_line.push(' ');
22761                    current_line_len += 1;
22762                }
22763            }
22764        }
22765    }
22766
22767    if !current_line.is_empty() {
22768        wrapped_text.push_str(&current_line);
22769    }
22770    wrapped_text
22771}
22772
22773#[test]
22774fn test_wrap_with_prefix() {
22775    assert_eq!(
22776        wrap_with_prefix(
22777            "# ".to_string(),
22778            "# ".to_string(),
22779            "abcdefg".to_string(),
22780            4,
22781            NonZeroU32::new(4).unwrap(),
22782            false,
22783        ),
22784        "# abcdefg"
22785    );
22786    assert_eq!(
22787        wrap_with_prefix(
22788            "".to_string(),
22789            "".to_string(),
22790            "\thello world".to_string(),
22791            8,
22792            NonZeroU32::new(4).unwrap(),
22793            false,
22794        ),
22795        "hello\nworld"
22796    );
22797    assert_eq!(
22798        wrap_with_prefix(
22799            "// ".to_string(),
22800            "// ".to_string(),
22801            "xx \nyy zz aa bb cc".to_string(),
22802            12,
22803            NonZeroU32::new(4).unwrap(),
22804            false,
22805        ),
22806        "// xx yy zz\n// aa bb cc"
22807    );
22808    assert_eq!(
22809        wrap_with_prefix(
22810            String::new(),
22811            String::new(),
22812            "这是什么 \n 钢笔".to_string(),
22813            3,
22814            NonZeroU32::new(4).unwrap(),
22815            false,
22816        ),
22817        "这是什\n么 钢\n"
22818    );
22819    assert_eq!(
22820        wrap_with_prefix(
22821            String::new(),
22822            String::new(),
22823            format!("foo{}bar", '\u{2009}'), // thin space
22824            80,
22825            NonZeroU32::new(4).unwrap(),
22826            false,
22827        ),
22828        format!("foo{}bar", '\u{2009}')
22829    );
22830}
22831
22832pub trait CollaborationHub {
22833    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22834    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22835    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22836}
22837
22838impl CollaborationHub for Entity<Project> {
22839    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22840        self.read(cx).collaborators()
22841    }
22842
22843    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22844        self.read(cx).user_store().read(cx).participant_indices()
22845    }
22846
22847    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22848        let this = self.read(cx);
22849        let user_ids = this.collaborators().values().map(|c| c.user_id);
22850        this.user_store().read(cx).participant_names(user_ids, cx)
22851    }
22852}
22853
22854pub trait SemanticsProvider {
22855    fn hover(
22856        &self,
22857        buffer: &Entity<Buffer>,
22858        position: text::Anchor,
22859        cx: &mut App,
22860    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22861
22862    fn inline_values(
22863        &self,
22864        buffer_handle: Entity<Buffer>,
22865        range: Range<text::Anchor>,
22866        cx: &mut App,
22867    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22868
22869    fn inlay_hints(
22870        &self,
22871        buffer_handle: Entity<Buffer>,
22872        range: Range<text::Anchor>,
22873        cx: &mut App,
22874    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22875
22876    fn resolve_inlay_hint(
22877        &self,
22878        hint: InlayHint,
22879        buffer_handle: Entity<Buffer>,
22880        server_id: LanguageServerId,
22881        cx: &mut App,
22882    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22883
22884    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22885
22886    fn document_highlights(
22887        &self,
22888        buffer: &Entity<Buffer>,
22889        position: text::Anchor,
22890        cx: &mut App,
22891    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22892
22893    fn definitions(
22894        &self,
22895        buffer: &Entity<Buffer>,
22896        position: text::Anchor,
22897        kind: GotoDefinitionKind,
22898        cx: &mut App,
22899    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22900
22901    fn range_for_rename(
22902        &self,
22903        buffer: &Entity<Buffer>,
22904        position: text::Anchor,
22905        cx: &mut App,
22906    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22907
22908    fn perform_rename(
22909        &self,
22910        buffer: &Entity<Buffer>,
22911        position: text::Anchor,
22912        new_name: String,
22913        cx: &mut App,
22914    ) -> Option<Task<Result<ProjectTransaction>>>;
22915}
22916
22917pub trait CompletionProvider {
22918    fn completions(
22919        &self,
22920        excerpt_id: ExcerptId,
22921        buffer: &Entity<Buffer>,
22922        buffer_position: text::Anchor,
22923        trigger: CompletionContext,
22924        window: &mut Window,
22925        cx: &mut Context<Editor>,
22926    ) -> Task<Result<Vec<CompletionResponse>>>;
22927
22928    fn resolve_completions(
22929        &self,
22930        _buffer: Entity<Buffer>,
22931        _completion_indices: Vec<usize>,
22932        _completions: Rc<RefCell<Box<[Completion]>>>,
22933        _cx: &mut Context<Editor>,
22934    ) -> Task<Result<bool>> {
22935        Task::ready(Ok(false))
22936    }
22937
22938    fn apply_additional_edits_for_completion(
22939        &self,
22940        _buffer: Entity<Buffer>,
22941        _completions: Rc<RefCell<Box<[Completion]>>>,
22942        _completion_index: usize,
22943        _push_to_history: bool,
22944        _cx: &mut Context<Editor>,
22945    ) -> Task<Result<Option<language::Transaction>>> {
22946        Task::ready(Ok(None))
22947    }
22948
22949    fn is_completion_trigger(
22950        &self,
22951        buffer: &Entity<Buffer>,
22952        position: language::Anchor,
22953        text: &str,
22954        trigger_in_words: bool,
22955        menu_is_open: bool,
22956        cx: &mut Context<Editor>,
22957    ) -> bool;
22958
22959    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22960
22961    fn sort_completions(&self) -> bool {
22962        true
22963    }
22964
22965    fn filter_completions(&self) -> bool {
22966        true
22967    }
22968}
22969
22970pub trait CodeActionProvider {
22971    fn id(&self) -> Arc<str>;
22972
22973    fn code_actions(
22974        &self,
22975        buffer: &Entity<Buffer>,
22976        range: Range<text::Anchor>,
22977        window: &mut Window,
22978        cx: &mut App,
22979    ) -> Task<Result<Vec<CodeAction>>>;
22980
22981    fn apply_code_action(
22982        &self,
22983        buffer_handle: Entity<Buffer>,
22984        action: CodeAction,
22985        excerpt_id: ExcerptId,
22986        push_to_history: bool,
22987        window: &mut Window,
22988        cx: &mut App,
22989    ) -> Task<Result<ProjectTransaction>>;
22990}
22991
22992impl CodeActionProvider for Entity<Project> {
22993    fn id(&self) -> Arc<str> {
22994        "project".into()
22995    }
22996
22997    fn code_actions(
22998        &self,
22999        buffer: &Entity<Buffer>,
23000        range: Range<text::Anchor>,
23001        _window: &mut Window,
23002        cx: &mut App,
23003    ) -> Task<Result<Vec<CodeAction>>> {
23004        self.update(cx, |project, cx| {
23005            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23006            let code_actions = project.code_actions(buffer, range, None, cx);
23007            cx.background_spawn(async move {
23008                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23009                Ok(code_lens_actions
23010                    .context("code lens fetch")?
23011                    .into_iter()
23012                    .flatten()
23013                    .chain(
23014                        code_actions
23015                            .context("code action fetch")?
23016                            .into_iter()
23017                            .flatten(),
23018                    )
23019                    .collect())
23020            })
23021        })
23022    }
23023
23024    fn apply_code_action(
23025        &self,
23026        buffer_handle: Entity<Buffer>,
23027        action: CodeAction,
23028        _excerpt_id: ExcerptId,
23029        push_to_history: bool,
23030        _window: &mut Window,
23031        cx: &mut App,
23032    ) -> Task<Result<ProjectTransaction>> {
23033        self.update(cx, |project, cx| {
23034            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23035        })
23036    }
23037}
23038
23039fn snippet_completions(
23040    project: &Project,
23041    buffer: &Entity<Buffer>,
23042    buffer_position: text::Anchor,
23043    cx: &mut App,
23044) -> Task<Result<CompletionResponse>> {
23045    let languages = buffer.read(cx).languages_at(buffer_position);
23046    let snippet_store = project.snippets().read(cx);
23047
23048    let scopes: Vec<_> = languages
23049        .iter()
23050        .filter_map(|language| {
23051            let language_name = language.lsp_id();
23052            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23053
23054            if snippets.is_empty() {
23055                None
23056            } else {
23057                Some((language.default_scope(), snippets))
23058            }
23059        })
23060        .collect();
23061
23062    if scopes.is_empty() {
23063        return Task::ready(Ok(CompletionResponse {
23064            completions: vec![],
23065            display_options: CompletionDisplayOptions::default(),
23066            is_incomplete: false,
23067        }));
23068    }
23069
23070    let snapshot = buffer.read(cx).text_snapshot();
23071    let executor = cx.background_executor().clone();
23072
23073    cx.background_spawn(async move {
23074        let mut is_incomplete = false;
23075        let mut completions: Vec<Completion> = Vec::new();
23076        for (scope, snippets) in scopes.into_iter() {
23077            let classifier =
23078                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23079
23080            const MAX_WORD_PREFIX_LEN: usize = 128;
23081            let last_word: String = snapshot
23082                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23083                .take(MAX_WORD_PREFIX_LEN)
23084                .take_while(|c| classifier.is_word(*c))
23085                .collect::<String>()
23086                .chars()
23087                .rev()
23088                .collect();
23089
23090            if last_word.is_empty() {
23091                return Ok(CompletionResponse {
23092                    completions: vec![],
23093                    display_options: CompletionDisplayOptions::default(),
23094                    is_incomplete: true,
23095                });
23096            }
23097
23098            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23099            let to_lsp = |point: &text::Anchor| {
23100                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23101                point_to_lsp(end)
23102            };
23103            let lsp_end = to_lsp(&buffer_position);
23104
23105            let candidates = snippets
23106                .iter()
23107                .enumerate()
23108                .flat_map(|(ix, snippet)| {
23109                    snippet
23110                        .prefix
23111                        .iter()
23112                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23113                })
23114                .collect::<Vec<StringMatchCandidate>>();
23115
23116            const MAX_RESULTS: usize = 100;
23117            let mut matches = fuzzy::match_strings(
23118                &candidates,
23119                &last_word,
23120                last_word.chars().any(|c| c.is_uppercase()),
23121                true,
23122                MAX_RESULTS,
23123                &Default::default(),
23124                executor.clone(),
23125            )
23126            .await;
23127
23128            if matches.len() >= MAX_RESULTS {
23129                is_incomplete = true;
23130            }
23131
23132            // Remove all candidates where the query's start does not match the start of any word in the candidate
23133            if let Some(query_start) = last_word.chars().next() {
23134                matches.retain(|string_match| {
23135                    split_words(&string_match.string).any(|word| {
23136                        // Check that the first codepoint of the word as lowercase matches the first
23137                        // codepoint of the query as lowercase
23138                        word.chars()
23139                            .flat_map(|codepoint| codepoint.to_lowercase())
23140                            .zip(query_start.to_lowercase())
23141                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23142                    })
23143                });
23144            }
23145
23146            let matched_strings = matches
23147                .into_iter()
23148                .map(|m| m.string)
23149                .collect::<HashSet<_>>();
23150
23151            completions.extend(snippets.iter().filter_map(|snippet| {
23152                let matching_prefix = snippet
23153                    .prefix
23154                    .iter()
23155                    .find(|prefix| matched_strings.contains(*prefix))?;
23156                let start = as_offset - last_word.len();
23157                let start = snapshot.anchor_before(start);
23158                let range = start..buffer_position;
23159                let lsp_start = to_lsp(&start);
23160                let lsp_range = lsp::Range {
23161                    start: lsp_start,
23162                    end: lsp_end,
23163                };
23164                Some(Completion {
23165                    replace_range: range,
23166                    new_text: snippet.body.clone(),
23167                    source: CompletionSource::Lsp {
23168                        insert_range: None,
23169                        server_id: LanguageServerId(usize::MAX),
23170                        resolved: true,
23171                        lsp_completion: Box::new(lsp::CompletionItem {
23172                            label: snippet.prefix.first().unwrap().clone(),
23173                            kind: Some(CompletionItemKind::SNIPPET),
23174                            label_details: snippet.description.as_ref().map(|description| {
23175                                lsp::CompletionItemLabelDetails {
23176                                    detail: Some(description.clone()),
23177                                    description: None,
23178                                }
23179                            }),
23180                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23181                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23182                                lsp::InsertReplaceEdit {
23183                                    new_text: snippet.body.clone(),
23184                                    insert: lsp_range,
23185                                    replace: lsp_range,
23186                                },
23187                            )),
23188                            filter_text: Some(snippet.body.clone()),
23189                            sort_text: Some(char::MAX.to_string()),
23190                            ..lsp::CompletionItem::default()
23191                        }),
23192                        lsp_defaults: None,
23193                    },
23194                    label: CodeLabel::plain(matching_prefix.clone(), None),
23195                    icon_path: None,
23196                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23197                        single_line: snippet.name.clone().into(),
23198                        plain_text: snippet
23199                            .description
23200                            .clone()
23201                            .map(|description| description.into()),
23202                    }),
23203                    insert_text_mode: None,
23204                    confirm: None,
23205                })
23206            }))
23207        }
23208
23209        Ok(CompletionResponse {
23210            completions,
23211            display_options: CompletionDisplayOptions::default(),
23212            is_incomplete,
23213        })
23214    })
23215}
23216
23217impl CompletionProvider for Entity<Project> {
23218    fn completions(
23219        &self,
23220        _excerpt_id: ExcerptId,
23221        buffer: &Entity<Buffer>,
23222        buffer_position: text::Anchor,
23223        options: CompletionContext,
23224        _window: &mut Window,
23225        cx: &mut Context<Editor>,
23226    ) -> Task<Result<Vec<CompletionResponse>>> {
23227        self.update(cx, |project, cx| {
23228            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23229            let project_completions = project.completions(buffer, buffer_position, options, cx);
23230            cx.background_spawn(async move {
23231                let mut responses = project_completions.await?;
23232                let snippets = snippets.await?;
23233                if !snippets.completions.is_empty() {
23234                    responses.push(snippets);
23235                }
23236                Ok(responses)
23237            })
23238        })
23239    }
23240
23241    fn resolve_completions(
23242        &self,
23243        buffer: Entity<Buffer>,
23244        completion_indices: Vec<usize>,
23245        completions: Rc<RefCell<Box<[Completion]>>>,
23246        cx: &mut Context<Editor>,
23247    ) -> Task<Result<bool>> {
23248        self.update(cx, |project, cx| {
23249            project.lsp_store().update(cx, |lsp_store, cx| {
23250                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23251            })
23252        })
23253    }
23254
23255    fn apply_additional_edits_for_completion(
23256        &self,
23257        buffer: Entity<Buffer>,
23258        completions: Rc<RefCell<Box<[Completion]>>>,
23259        completion_index: usize,
23260        push_to_history: bool,
23261        cx: &mut Context<Editor>,
23262    ) -> Task<Result<Option<language::Transaction>>> {
23263        self.update(cx, |project, cx| {
23264            project.lsp_store().update(cx, |lsp_store, cx| {
23265                lsp_store.apply_additional_edits_for_completion(
23266                    buffer,
23267                    completions,
23268                    completion_index,
23269                    push_to_history,
23270                    cx,
23271                )
23272            })
23273        })
23274    }
23275
23276    fn is_completion_trigger(
23277        &self,
23278        buffer: &Entity<Buffer>,
23279        position: language::Anchor,
23280        text: &str,
23281        trigger_in_words: bool,
23282        menu_is_open: bool,
23283        cx: &mut Context<Editor>,
23284    ) -> bool {
23285        let mut chars = text.chars();
23286        let char = if let Some(char) = chars.next() {
23287            char
23288        } else {
23289            return false;
23290        };
23291        if chars.next().is_some() {
23292            return false;
23293        }
23294
23295        let buffer = buffer.read(cx);
23296        let snapshot = buffer.snapshot();
23297        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23298            return false;
23299        }
23300        let classifier = snapshot
23301            .char_classifier_at(position)
23302            .scope_context(Some(CharScopeContext::Completion));
23303        if trigger_in_words && classifier.is_word(char) {
23304            return true;
23305        }
23306
23307        buffer.completion_triggers().contains(text)
23308    }
23309}
23310
23311impl SemanticsProvider for Entity<Project> {
23312    fn hover(
23313        &self,
23314        buffer: &Entity<Buffer>,
23315        position: text::Anchor,
23316        cx: &mut App,
23317    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23318        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23319    }
23320
23321    fn document_highlights(
23322        &self,
23323        buffer: &Entity<Buffer>,
23324        position: text::Anchor,
23325        cx: &mut App,
23326    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23327        Some(self.update(cx, |project, cx| {
23328            project.document_highlights(buffer, position, cx)
23329        }))
23330    }
23331
23332    fn definitions(
23333        &self,
23334        buffer: &Entity<Buffer>,
23335        position: text::Anchor,
23336        kind: GotoDefinitionKind,
23337        cx: &mut App,
23338    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23339        Some(self.update(cx, |project, cx| match kind {
23340            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23341            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23342            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23343            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23344        }))
23345    }
23346
23347    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23348        self.update(cx, |project, cx| {
23349            if project
23350                .active_debug_session(cx)
23351                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23352            {
23353                return true;
23354            }
23355
23356            buffer.update(cx, |buffer, cx| {
23357                project.any_language_server_supports_inlay_hints(buffer, cx)
23358            })
23359        })
23360    }
23361
23362    fn inline_values(
23363        &self,
23364        buffer_handle: Entity<Buffer>,
23365        range: Range<text::Anchor>,
23366        cx: &mut App,
23367    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23368        self.update(cx, |project, cx| {
23369            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23370
23371            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23372        })
23373    }
23374
23375    fn inlay_hints(
23376        &self,
23377        buffer_handle: Entity<Buffer>,
23378        range: Range<text::Anchor>,
23379        cx: &mut App,
23380    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23381        Some(self.update(cx, |project, cx| {
23382            project.inlay_hints(buffer_handle, range, cx)
23383        }))
23384    }
23385
23386    fn resolve_inlay_hint(
23387        &self,
23388        hint: InlayHint,
23389        buffer_handle: Entity<Buffer>,
23390        server_id: LanguageServerId,
23391        cx: &mut App,
23392    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23393        Some(self.update(cx, |project, cx| {
23394            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23395        }))
23396    }
23397
23398    fn range_for_rename(
23399        &self,
23400        buffer: &Entity<Buffer>,
23401        position: text::Anchor,
23402        cx: &mut App,
23403    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23404        Some(self.update(cx, |project, cx| {
23405            let buffer = buffer.clone();
23406            let task = project.prepare_rename(buffer.clone(), position, cx);
23407            cx.spawn(async move |_, cx| {
23408                Ok(match task.await? {
23409                    PrepareRenameResponse::Success(range) => Some(range),
23410                    PrepareRenameResponse::InvalidPosition => None,
23411                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23412                        // Fallback on using TreeSitter info to determine identifier range
23413                        buffer.read_with(cx, |buffer, _| {
23414                            let snapshot = buffer.snapshot();
23415                            let (range, kind) = snapshot.surrounding_word(position, None);
23416                            if kind != Some(CharKind::Word) {
23417                                return None;
23418                            }
23419                            Some(
23420                                snapshot.anchor_before(range.start)
23421                                    ..snapshot.anchor_after(range.end),
23422                            )
23423                        })?
23424                    }
23425                })
23426            })
23427        }))
23428    }
23429
23430    fn perform_rename(
23431        &self,
23432        buffer: &Entity<Buffer>,
23433        position: text::Anchor,
23434        new_name: String,
23435        cx: &mut App,
23436    ) -> Option<Task<Result<ProjectTransaction>>> {
23437        Some(self.update(cx, |project, cx| {
23438            project.perform_rename(buffer.clone(), position, new_name, cx)
23439        }))
23440    }
23441}
23442
23443fn inlay_hint_settings(
23444    location: Anchor,
23445    snapshot: &MultiBufferSnapshot,
23446    cx: &mut Context<Editor>,
23447) -> InlayHintSettings {
23448    let file = snapshot.file_at(location);
23449    let language = snapshot.language_at(location).map(|l| l.name());
23450    language_settings(language, file, cx).inlay_hints
23451}
23452
23453fn consume_contiguous_rows(
23454    contiguous_row_selections: &mut Vec<Selection<Point>>,
23455    selection: &Selection<Point>,
23456    display_map: &DisplaySnapshot,
23457    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23458) -> (MultiBufferRow, MultiBufferRow) {
23459    contiguous_row_selections.push(selection.clone());
23460    let start_row = starting_row(selection, display_map);
23461    let mut end_row = ending_row(selection, display_map);
23462
23463    while let Some(next_selection) = selections.peek() {
23464        if next_selection.start.row <= end_row.0 {
23465            end_row = ending_row(next_selection, display_map);
23466            contiguous_row_selections.push(selections.next().unwrap().clone());
23467        } else {
23468            break;
23469        }
23470    }
23471    (start_row, end_row)
23472}
23473
23474fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23475    if selection.start.column > 0 {
23476        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23477    } else {
23478        MultiBufferRow(selection.start.row)
23479    }
23480}
23481
23482fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23483    if next_selection.end.column > 0 || next_selection.is_empty() {
23484        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23485    } else {
23486        MultiBufferRow(next_selection.end.row)
23487    }
23488}
23489
23490impl EditorSnapshot {
23491    pub fn remote_selections_in_range<'a>(
23492        &'a self,
23493        range: &'a Range<Anchor>,
23494        collaboration_hub: &dyn CollaborationHub,
23495        cx: &'a App,
23496    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23497        let participant_names = collaboration_hub.user_names(cx);
23498        let participant_indices = collaboration_hub.user_participant_indices(cx);
23499        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23500        let collaborators_by_replica_id = collaborators_by_peer_id
23501            .values()
23502            .map(|collaborator| (collaborator.replica_id, collaborator))
23503            .collect::<HashMap<_, _>>();
23504        self.buffer_snapshot()
23505            .selections_in_range(range, false)
23506            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23507                if replica_id == ReplicaId::AGENT {
23508                    Some(RemoteSelection {
23509                        replica_id,
23510                        selection,
23511                        cursor_shape,
23512                        line_mode,
23513                        collaborator_id: CollaboratorId::Agent,
23514                        user_name: Some("Agent".into()),
23515                        color: cx.theme().players().agent(),
23516                    })
23517                } else {
23518                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23519                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23520                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23521                    Some(RemoteSelection {
23522                        replica_id,
23523                        selection,
23524                        cursor_shape,
23525                        line_mode,
23526                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23527                        user_name,
23528                        color: if let Some(index) = participant_index {
23529                            cx.theme().players().color_for_participant(index.0)
23530                        } else {
23531                            cx.theme().players().absent()
23532                        },
23533                    })
23534                }
23535            })
23536    }
23537
23538    pub fn hunks_for_ranges(
23539        &self,
23540        ranges: impl IntoIterator<Item = Range<Point>>,
23541    ) -> Vec<MultiBufferDiffHunk> {
23542        let mut hunks = Vec::new();
23543        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23544            HashMap::default();
23545        for query_range in ranges {
23546            let query_rows =
23547                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23548            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23549                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23550            ) {
23551                // Include deleted hunks that are adjacent to the query range, because
23552                // otherwise they would be missed.
23553                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23554                if hunk.status().is_deleted() {
23555                    intersects_range |= hunk.row_range.start == query_rows.end;
23556                    intersects_range |= hunk.row_range.end == query_rows.start;
23557                }
23558                if intersects_range {
23559                    if !processed_buffer_rows
23560                        .entry(hunk.buffer_id)
23561                        .or_default()
23562                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23563                    {
23564                        continue;
23565                    }
23566                    hunks.push(hunk);
23567                }
23568            }
23569        }
23570
23571        hunks
23572    }
23573
23574    fn display_diff_hunks_for_rows<'a>(
23575        &'a self,
23576        display_rows: Range<DisplayRow>,
23577        folded_buffers: &'a HashSet<BufferId>,
23578    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23579        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23580        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23581
23582        self.buffer_snapshot()
23583            .diff_hunks_in_range(buffer_start..buffer_end)
23584            .filter_map(|hunk| {
23585                if folded_buffers.contains(&hunk.buffer_id) {
23586                    return None;
23587                }
23588
23589                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23590                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23591
23592                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23593                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23594
23595                let display_hunk = if hunk_display_start.column() != 0 {
23596                    DisplayDiffHunk::Folded {
23597                        display_row: hunk_display_start.row(),
23598                    }
23599                } else {
23600                    let mut end_row = hunk_display_end.row();
23601                    if hunk_display_end.column() > 0 {
23602                        end_row.0 += 1;
23603                    }
23604                    let is_created_file = hunk.is_created_file();
23605                    DisplayDiffHunk::Unfolded {
23606                        status: hunk.status(),
23607                        diff_base_byte_range: hunk.diff_base_byte_range,
23608                        display_row_range: hunk_display_start.row()..end_row,
23609                        multi_buffer_range: Anchor::range_in_buffer(
23610                            hunk.excerpt_id,
23611                            hunk.buffer_id,
23612                            hunk.buffer_range,
23613                        ),
23614                        is_created_file,
23615                    }
23616                };
23617
23618                Some(display_hunk)
23619            })
23620    }
23621
23622    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23623        self.display_snapshot
23624            .buffer_snapshot()
23625            .language_at(position)
23626    }
23627
23628    pub fn is_focused(&self) -> bool {
23629        self.is_focused
23630    }
23631
23632    pub fn placeholder_text(&self) -> Option<String> {
23633        self.placeholder_display_snapshot
23634            .as_ref()
23635            .map(|display_map| display_map.text())
23636    }
23637
23638    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23639        self.scroll_anchor.scroll_position(&self.display_snapshot)
23640    }
23641
23642    fn gutter_dimensions(
23643        &self,
23644        font_id: FontId,
23645        font_size: Pixels,
23646        max_line_number_width: Pixels,
23647        cx: &App,
23648    ) -> Option<GutterDimensions> {
23649        if !self.show_gutter {
23650            return None;
23651        }
23652
23653        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23654        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23655
23656        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23657            matches!(
23658                ProjectSettings::get_global(cx).git.git_gutter,
23659                GitGutterSetting::TrackedFiles
23660            )
23661        });
23662        let gutter_settings = EditorSettings::get_global(cx).gutter;
23663        let show_line_numbers = self
23664            .show_line_numbers
23665            .unwrap_or(gutter_settings.line_numbers);
23666        let line_gutter_width = if show_line_numbers {
23667            // Avoid flicker-like gutter resizes when the line number gains another digit by
23668            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23669            let min_width_for_number_on_gutter =
23670                ch_advance * gutter_settings.min_line_number_digits as f32;
23671            max_line_number_width.max(min_width_for_number_on_gutter)
23672        } else {
23673            0.0.into()
23674        };
23675
23676        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23677        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23678
23679        let git_blame_entries_width =
23680            self.git_blame_gutter_max_author_length
23681                .map(|max_author_length| {
23682                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23683                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23684
23685                    /// The number of characters to dedicate to gaps and margins.
23686                    const SPACING_WIDTH: usize = 4;
23687
23688                    let max_char_count = max_author_length.min(renderer.max_author_length())
23689                        + ::git::SHORT_SHA_LENGTH
23690                        + MAX_RELATIVE_TIMESTAMP.len()
23691                        + SPACING_WIDTH;
23692
23693                    ch_advance * max_char_count
23694                });
23695
23696        let is_singleton = self.buffer_snapshot().is_singleton();
23697
23698        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23699        left_padding += if !is_singleton {
23700            ch_width * 4.0
23701        } else if show_runnables || show_breakpoints {
23702            ch_width * 3.0
23703        } else if show_git_gutter && show_line_numbers {
23704            ch_width * 2.0
23705        } else if show_git_gutter || show_line_numbers {
23706            ch_width
23707        } else {
23708            px(0.)
23709        };
23710
23711        let shows_folds = is_singleton && gutter_settings.folds;
23712
23713        let right_padding = if shows_folds && show_line_numbers {
23714            ch_width * 4.0
23715        } else if shows_folds || (!is_singleton && show_line_numbers) {
23716            ch_width * 3.0
23717        } else if show_line_numbers {
23718            ch_width
23719        } else {
23720            px(0.)
23721        };
23722
23723        Some(GutterDimensions {
23724            left_padding,
23725            right_padding,
23726            width: line_gutter_width + left_padding + right_padding,
23727            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23728            git_blame_entries_width,
23729        })
23730    }
23731
23732    pub fn render_crease_toggle(
23733        &self,
23734        buffer_row: MultiBufferRow,
23735        row_contains_cursor: bool,
23736        editor: Entity<Editor>,
23737        window: &mut Window,
23738        cx: &mut App,
23739    ) -> Option<AnyElement> {
23740        let folded = self.is_line_folded(buffer_row);
23741        let mut is_foldable = false;
23742
23743        if let Some(crease) = self
23744            .crease_snapshot
23745            .query_row(buffer_row, self.buffer_snapshot())
23746        {
23747            is_foldable = true;
23748            match crease {
23749                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23750                    if let Some(render_toggle) = render_toggle {
23751                        let toggle_callback =
23752                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23753                                if folded {
23754                                    editor.update(cx, |editor, cx| {
23755                                        editor.fold_at(buffer_row, window, cx)
23756                                    });
23757                                } else {
23758                                    editor.update(cx, |editor, cx| {
23759                                        editor.unfold_at(buffer_row, window, cx)
23760                                    });
23761                                }
23762                            });
23763                        return Some((render_toggle)(
23764                            buffer_row,
23765                            folded,
23766                            toggle_callback,
23767                            window,
23768                            cx,
23769                        ));
23770                    }
23771                }
23772            }
23773        }
23774
23775        is_foldable |= self.starts_indent(buffer_row);
23776
23777        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23778            Some(
23779                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23780                    .toggle_state(folded)
23781                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23782                        if folded {
23783                            this.unfold_at(buffer_row, window, cx);
23784                        } else {
23785                            this.fold_at(buffer_row, window, cx);
23786                        }
23787                    }))
23788                    .into_any_element(),
23789            )
23790        } else {
23791            None
23792        }
23793    }
23794
23795    pub fn render_crease_trailer(
23796        &self,
23797        buffer_row: MultiBufferRow,
23798        window: &mut Window,
23799        cx: &mut App,
23800    ) -> Option<AnyElement> {
23801        let folded = self.is_line_folded(buffer_row);
23802        if let Crease::Inline { render_trailer, .. } = self
23803            .crease_snapshot
23804            .query_row(buffer_row, self.buffer_snapshot())?
23805        {
23806            let render_trailer = render_trailer.as_ref()?;
23807            Some(render_trailer(buffer_row, folded, window, cx))
23808        } else {
23809            None
23810        }
23811    }
23812}
23813
23814impl Deref for EditorSnapshot {
23815    type Target = DisplaySnapshot;
23816
23817    fn deref(&self) -> &Self::Target {
23818        &self.display_snapshot
23819    }
23820}
23821
23822#[derive(Clone, Debug, PartialEq, Eq)]
23823pub enum EditorEvent {
23824    InputIgnored {
23825        text: Arc<str>,
23826    },
23827    InputHandled {
23828        utf16_range_to_replace: Option<Range<isize>>,
23829        text: Arc<str>,
23830    },
23831    ExcerptsAdded {
23832        buffer: Entity<Buffer>,
23833        predecessor: ExcerptId,
23834        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23835    },
23836    ExcerptsRemoved {
23837        ids: Vec<ExcerptId>,
23838        removed_buffer_ids: Vec<BufferId>,
23839    },
23840    BufferFoldToggled {
23841        ids: Vec<ExcerptId>,
23842        folded: bool,
23843    },
23844    ExcerptsEdited {
23845        ids: Vec<ExcerptId>,
23846    },
23847    ExcerptsExpanded {
23848        ids: Vec<ExcerptId>,
23849    },
23850    BufferEdited,
23851    Edited {
23852        transaction_id: clock::Lamport,
23853    },
23854    Reparsed(BufferId),
23855    Focused,
23856    FocusedIn,
23857    Blurred,
23858    DirtyChanged,
23859    Saved,
23860    TitleChanged,
23861    SelectionsChanged {
23862        local: bool,
23863    },
23864    ScrollPositionChanged {
23865        local: bool,
23866        autoscroll: bool,
23867    },
23868    TransactionUndone {
23869        transaction_id: clock::Lamport,
23870    },
23871    TransactionBegun {
23872        transaction_id: clock::Lamport,
23873    },
23874    CursorShapeChanged,
23875    BreadcrumbsChanged,
23876    PushedToNavHistory {
23877        anchor: Anchor,
23878        is_deactivate: bool,
23879    },
23880}
23881
23882impl EventEmitter<EditorEvent> for Editor {}
23883
23884impl Focusable for Editor {
23885    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23886        self.focus_handle.clone()
23887    }
23888}
23889
23890impl Render for Editor {
23891    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23892        let settings = ThemeSettings::get_global(cx);
23893
23894        let mut text_style = match self.mode {
23895            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23896                color: cx.theme().colors().editor_foreground,
23897                font_family: settings.ui_font.family.clone(),
23898                font_features: settings.ui_font.features.clone(),
23899                font_fallbacks: settings.ui_font.fallbacks.clone(),
23900                font_size: rems(0.875).into(),
23901                font_weight: settings.ui_font.weight,
23902                line_height: relative(settings.buffer_line_height.value()),
23903                ..Default::default()
23904            },
23905            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23906                color: cx.theme().colors().editor_foreground,
23907                font_family: settings.buffer_font.family.clone(),
23908                font_features: settings.buffer_font.features.clone(),
23909                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23910                font_size: settings.buffer_font_size(cx).into(),
23911                font_weight: settings.buffer_font.weight,
23912                line_height: relative(settings.buffer_line_height.value()),
23913                ..Default::default()
23914            },
23915        };
23916        if let Some(text_style_refinement) = &self.text_style_refinement {
23917            text_style.refine(text_style_refinement)
23918        }
23919
23920        let background = match self.mode {
23921            EditorMode::SingleLine => cx.theme().system().transparent,
23922            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23923            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23924            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23925        };
23926
23927        EditorElement::new(
23928            &cx.entity(),
23929            EditorStyle {
23930                background,
23931                border: cx.theme().colors().border,
23932                local_player: cx.theme().players().local(),
23933                text: text_style,
23934                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23935                syntax: cx.theme().syntax().clone(),
23936                status: cx.theme().status().clone(),
23937                inlay_hints_style: make_inlay_hints_style(cx),
23938                edit_prediction_styles: make_suggestion_styles(cx),
23939                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23940                show_underlines: self.diagnostics_enabled(),
23941            },
23942        )
23943    }
23944}
23945
23946impl EntityInputHandler for Editor {
23947    fn text_for_range(
23948        &mut self,
23949        range_utf16: Range<usize>,
23950        adjusted_range: &mut Option<Range<usize>>,
23951        _: &mut Window,
23952        cx: &mut Context<Self>,
23953    ) -> Option<String> {
23954        let snapshot = self.buffer.read(cx).read(cx);
23955        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23956        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23957        if (start.0..end.0) != range_utf16 {
23958            adjusted_range.replace(start.0..end.0);
23959        }
23960        Some(snapshot.text_for_range(start..end).collect())
23961    }
23962
23963    fn selected_text_range(
23964        &mut self,
23965        ignore_disabled_input: bool,
23966        _: &mut Window,
23967        cx: &mut Context<Self>,
23968    ) -> Option<UTF16Selection> {
23969        // Prevent the IME menu from appearing when holding down an alphabetic key
23970        // while input is disabled.
23971        if !ignore_disabled_input && !self.input_enabled {
23972            return None;
23973        }
23974
23975        let selection = self
23976            .selections
23977            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23978        let range = selection.range();
23979
23980        Some(UTF16Selection {
23981            range: range.start.0..range.end.0,
23982            reversed: selection.reversed,
23983        })
23984    }
23985
23986    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23987        let snapshot = self.buffer.read(cx).read(cx);
23988        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23989        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23990    }
23991
23992    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23993        self.clear_highlights::<InputComposition>(cx);
23994        self.ime_transaction.take();
23995    }
23996
23997    fn replace_text_in_range(
23998        &mut self,
23999        range_utf16: Option<Range<usize>>,
24000        text: &str,
24001        window: &mut Window,
24002        cx: &mut Context<Self>,
24003    ) {
24004        if !self.input_enabled {
24005            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24006            return;
24007        }
24008
24009        self.transact(window, cx, |this, window, cx| {
24010            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24011                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24012                Some(this.selection_replacement_ranges(range_utf16, cx))
24013            } else {
24014                this.marked_text_ranges(cx)
24015            };
24016
24017            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24018                let newest_selection_id = this.selections.newest_anchor().id;
24019                this.selections
24020                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24021                    .iter()
24022                    .zip(ranges_to_replace.iter())
24023                    .find_map(|(selection, range)| {
24024                        if selection.id == newest_selection_id {
24025                            Some(
24026                                (range.start.0 as isize - selection.head().0 as isize)
24027                                    ..(range.end.0 as isize - selection.head().0 as isize),
24028                            )
24029                        } else {
24030                            None
24031                        }
24032                    })
24033            });
24034
24035            cx.emit(EditorEvent::InputHandled {
24036                utf16_range_to_replace: range_to_replace,
24037                text: text.into(),
24038            });
24039
24040            if let Some(new_selected_ranges) = new_selected_ranges {
24041                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24042                    selections.select_ranges(new_selected_ranges)
24043                });
24044                this.backspace(&Default::default(), window, cx);
24045            }
24046
24047            this.handle_input(text, window, cx);
24048        });
24049
24050        if let Some(transaction) = self.ime_transaction {
24051            self.buffer.update(cx, |buffer, cx| {
24052                buffer.group_until_transaction(transaction, cx);
24053            });
24054        }
24055
24056        self.unmark_text(window, cx);
24057    }
24058
24059    fn replace_and_mark_text_in_range(
24060        &mut self,
24061        range_utf16: Option<Range<usize>>,
24062        text: &str,
24063        new_selected_range_utf16: Option<Range<usize>>,
24064        window: &mut Window,
24065        cx: &mut Context<Self>,
24066    ) {
24067        if !self.input_enabled {
24068            return;
24069        }
24070
24071        let transaction = self.transact(window, cx, |this, window, cx| {
24072            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24073                let snapshot = this.buffer.read(cx).read(cx);
24074                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24075                    for marked_range in &mut marked_ranges {
24076                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24077                        marked_range.start.0 += relative_range_utf16.start;
24078                        marked_range.start =
24079                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24080                        marked_range.end =
24081                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24082                    }
24083                }
24084                Some(marked_ranges)
24085            } else if let Some(range_utf16) = range_utf16 {
24086                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24087                Some(this.selection_replacement_ranges(range_utf16, cx))
24088            } else {
24089                None
24090            };
24091
24092            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24093                let newest_selection_id = this.selections.newest_anchor().id;
24094                this.selections
24095                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24096                    .iter()
24097                    .zip(ranges_to_replace.iter())
24098                    .find_map(|(selection, range)| {
24099                        if selection.id == newest_selection_id {
24100                            Some(
24101                                (range.start.0 as isize - selection.head().0 as isize)
24102                                    ..(range.end.0 as isize - selection.head().0 as isize),
24103                            )
24104                        } else {
24105                            None
24106                        }
24107                    })
24108            });
24109
24110            cx.emit(EditorEvent::InputHandled {
24111                utf16_range_to_replace: range_to_replace,
24112                text: text.into(),
24113            });
24114
24115            if let Some(ranges) = ranges_to_replace {
24116                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24117                    s.select_ranges(ranges)
24118                });
24119            }
24120
24121            let marked_ranges = {
24122                let snapshot = this.buffer.read(cx).read(cx);
24123                this.selections
24124                    .disjoint_anchors_arc()
24125                    .iter()
24126                    .map(|selection| {
24127                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24128                    })
24129                    .collect::<Vec<_>>()
24130            };
24131
24132            if text.is_empty() {
24133                this.unmark_text(window, cx);
24134            } else {
24135                this.highlight_text::<InputComposition>(
24136                    marked_ranges.clone(),
24137                    HighlightStyle {
24138                        underline: Some(UnderlineStyle {
24139                            thickness: px(1.),
24140                            color: None,
24141                            wavy: false,
24142                        }),
24143                        ..Default::default()
24144                    },
24145                    cx,
24146                );
24147            }
24148
24149            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24150            let use_autoclose = this.use_autoclose;
24151            let use_auto_surround = this.use_auto_surround;
24152            this.set_use_autoclose(false);
24153            this.set_use_auto_surround(false);
24154            this.handle_input(text, window, cx);
24155            this.set_use_autoclose(use_autoclose);
24156            this.set_use_auto_surround(use_auto_surround);
24157
24158            if let Some(new_selected_range) = new_selected_range_utf16 {
24159                let snapshot = this.buffer.read(cx).read(cx);
24160                let new_selected_ranges = marked_ranges
24161                    .into_iter()
24162                    .map(|marked_range| {
24163                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24164                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24165                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24166                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24167                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24168                    })
24169                    .collect::<Vec<_>>();
24170
24171                drop(snapshot);
24172                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24173                    selections.select_ranges(new_selected_ranges)
24174                });
24175            }
24176        });
24177
24178        self.ime_transaction = self.ime_transaction.or(transaction);
24179        if let Some(transaction) = self.ime_transaction {
24180            self.buffer.update(cx, |buffer, cx| {
24181                buffer.group_until_transaction(transaction, cx);
24182            });
24183        }
24184
24185        if self.text_highlights::<InputComposition>(cx).is_none() {
24186            self.ime_transaction.take();
24187        }
24188    }
24189
24190    fn bounds_for_range(
24191        &mut self,
24192        range_utf16: Range<usize>,
24193        element_bounds: gpui::Bounds<Pixels>,
24194        window: &mut Window,
24195        cx: &mut Context<Self>,
24196    ) -> Option<gpui::Bounds<Pixels>> {
24197        let text_layout_details = self.text_layout_details(window);
24198        let CharacterDimensions {
24199            em_width,
24200            em_advance,
24201            line_height,
24202        } = self.character_dimensions(window);
24203
24204        let snapshot = self.snapshot(window, cx);
24205        let scroll_position = snapshot.scroll_position();
24206        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24207
24208        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24209        let x = Pixels::from(
24210            ScrollOffset::from(
24211                snapshot.x_for_display_point(start, &text_layout_details)
24212                    + self.gutter_dimensions.full_width(),
24213            ) - scroll_left,
24214        );
24215        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24216
24217        Some(Bounds {
24218            origin: element_bounds.origin + point(x, y),
24219            size: size(em_width, line_height),
24220        })
24221    }
24222
24223    fn character_index_for_point(
24224        &mut self,
24225        point: gpui::Point<Pixels>,
24226        _window: &mut Window,
24227        _cx: &mut Context<Self>,
24228    ) -> Option<usize> {
24229        let position_map = self.last_position_map.as_ref()?;
24230        if !position_map.text_hitbox.contains(&point) {
24231            return None;
24232        }
24233        let display_point = position_map.point_for_position(point).previous_valid;
24234        let anchor = position_map
24235            .snapshot
24236            .display_point_to_anchor(display_point, Bias::Left);
24237        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24238        Some(utf16_offset.0)
24239    }
24240}
24241
24242trait SelectionExt {
24243    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24244    fn spanned_rows(
24245        &self,
24246        include_end_if_at_line_start: bool,
24247        map: &DisplaySnapshot,
24248    ) -> Range<MultiBufferRow>;
24249}
24250
24251impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24252    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24253        let start = self
24254            .start
24255            .to_point(map.buffer_snapshot())
24256            .to_display_point(map);
24257        let end = self
24258            .end
24259            .to_point(map.buffer_snapshot())
24260            .to_display_point(map);
24261        if self.reversed {
24262            end..start
24263        } else {
24264            start..end
24265        }
24266    }
24267
24268    fn spanned_rows(
24269        &self,
24270        include_end_if_at_line_start: bool,
24271        map: &DisplaySnapshot,
24272    ) -> Range<MultiBufferRow> {
24273        let start = self.start.to_point(map.buffer_snapshot());
24274        let mut end = self.end.to_point(map.buffer_snapshot());
24275        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24276            end.row -= 1;
24277        }
24278
24279        let buffer_start = map.prev_line_boundary(start).0;
24280        let buffer_end = map.next_line_boundary(end).0;
24281        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24282    }
24283}
24284
24285impl<T: InvalidationRegion> InvalidationStack<T> {
24286    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24287    where
24288        S: Clone + ToOffset,
24289    {
24290        while let Some(region) = self.last() {
24291            let all_selections_inside_invalidation_ranges =
24292                if selections.len() == region.ranges().len() {
24293                    selections
24294                        .iter()
24295                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24296                        .all(|(selection, invalidation_range)| {
24297                            let head = selection.head().to_offset(buffer);
24298                            invalidation_range.start <= head && invalidation_range.end >= head
24299                        })
24300                } else {
24301                    false
24302                };
24303
24304            if all_selections_inside_invalidation_ranges {
24305                break;
24306            } else {
24307                self.pop();
24308            }
24309        }
24310    }
24311}
24312
24313impl<T> Default for InvalidationStack<T> {
24314    fn default() -> Self {
24315        Self(Default::default())
24316    }
24317}
24318
24319impl<T> Deref for InvalidationStack<T> {
24320    type Target = Vec<T>;
24321
24322    fn deref(&self) -> &Self::Target {
24323        &self.0
24324    }
24325}
24326
24327impl<T> DerefMut for InvalidationStack<T> {
24328    fn deref_mut(&mut self) -> &mut Self::Target {
24329        &mut self.0
24330    }
24331}
24332
24333impl InvalidationRegion for SnippetState {
24334    fn ranges(&self) -> &[Range<Anchor>] {
24335        &self.ranges[self.active_index]
24336    }
24337}
24338
24339fn edit_prediction_edit_text(
24340    current_snapshot: &BufferSnapshot,
24341    edits: &[(Range<Anchor>, String)],
24342    edit_preview: &EditPreview,
24343    include_deletions: bool,
24344    cx: &App,
24345) -> HighlightedText {
24346    let edits = edits
24347        .iter()
24348        .map(|(anchor, text)| {
24349            (
24350                anchor.start.text_anchor..anchor.end.text_anchor,
24351                text.clone(),
24352            )
24353        })
24354        .collect::<Vec<_>>();
24355
24356    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24357}
24358
24359fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24360    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24361    // Just show the raw edit text with basic styling
24362    let mut text = String::new();
24363    let mut highlights = Vec::new();
24364
24365    let insertion_highlight_style = HighlightStyle {
24366        color: Some(cx.theme().colors().text),
24367        ..Default::default()
24368    };
24369
24370    for (_, edit_text) in edits {
24371        let start_offset = text.len();
24372        text.push_str(edit_text);
24373        let end_offset = text.len();
24374
24375        if start_offset < end_offset {
24376            highlights.push((start_offset..end_offset, insertion_highlight_style));
24377        }
24378    }
24379
24380    HighlightedText {
24381        text: text.into(),
24382        highlights,
24383    }
24384}
24385
24386pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24387    match severity {
24388        lsp::DiagnosticSeverity::ERROR => colors.error,
24389        lsp::DiagnosticSeverity::WARNING => colors.warning,
24390        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24391        lsp::DiagnosticSeverity::HINT => colors.info,
24392        _ => colors.ignored,
24393    }
24394}
24395
24396pub fn styled_runs_for_code_label<'a>(
24397    label: &'a CodeLabel,
24398    syntax_theme: &'a theme::SyntaxTheme,
24399) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24400    let fade_out = HighlightStyle {
24401        fade_out: Some(0.35),
24402        ..Default::default()
24403    };
24404
24405    let mut prev_end = label.filter_range.end;
24406    label
24407        .runs
24408        .iter()
24409        .enumerate()
24410        .flat_map(move |(ix, (range, highlight_id))| {
24411            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24412                style
24413            } else {
24414                return Default::default();
24415            };
24416            let muted_style = style.highlight(fade_out);
24417
24418            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24419            if range.start >= label.filter_range.end {
24420                if range.start > prev_end {
24421                    runs.push((prev_end..range.start, fade_out));
24422                }
24423                runs.push((range.clone(), muted_style));
24424            } else if range.end <= label.filter_range.end {
24425                runs.push((range.clone(), style));
24426            } else {
24427                runs.push((range.start..label.filter_range.end, style));
24428                runs.push((label.filter_range.end..range.end, muted_style));
24429            }
24430            prev_end = cmp::max(prev_end, range.end);
24431
24432            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24433                runs.push((prev_end..label.text.len(), fade_out));
24434            }
24435
24436            runs
24437        })
24438}
24439
24440pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24441    let mut prev_index = 0;
24442    let mut prev_codepoint: Option<char> = None;
24443    text.char_indices()
24444        .chain([(text.len(), '\0')])
24445        .filter_map(move |(index, codepoint)| {
24446            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24447            let is_boundary = index == text.len()
24448                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24449                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24450            if is_boundary {
24451                let chunk = &text[prev_index..index];
24452                prev_index = index;
24453                Some(chunk)
24454            } else {
24455                None
24456            }
24457        })
24458}
24459
24460pub trait RangeToAnchorExt: Sized {
24461    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24462
24463    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24464        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24465        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24466    }
24467}
24468
24469impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24470    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24471        let start_offset = self.start.to_offset(snapshot);
24472        let end_offset = self.end.to_offset(snapshot);
24473        if start_offset == end_offset {
24474            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24475        } else {
24476            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24477        }
24478    }
24479}
24480
24481pub trait RowExt {
24482    fn as_f64(&self) -> f64;
24483
24484    fn next_row(&self) -> Self;
24485
24486    fn previous_row(&self) -> Self;
24487
24488    fn minus(&self, other: Self) -> u32;
24489}
24490
24491impl RowExt for DisplayRow {
24492    fn as_f64(&self) -> f64 {
24493        self.0 as _
24494    }
24495
24496    fn next_row(&self) -> Self {
24497        Self(self.0 + 1)
24498    }
24499
24500    fn previous_row(&self) -> Self {
24501        Self(self.0.saturating_sub(1))
24502    }
24503
24504    fn minus(&self, other: Self) -> u32 {
24505        self.0 - other.0
24506    }
24507}
24508
24509impl RowExt for MultiBufferRow {
24510    fn as_f64(&self) -> f64 {
24511        self.0 as _
24512    }
24513
24514    fn next_row(&self) -> Self {
24515        Self(self.0 + 1)
24516    }
24517
24518    fn previous_row(&self) -> Self {
24519        Self(self.0.saturating_sub(1))
24520    }
24521
24522    fn minus(&self, other: Self) -> u32 {
24523        self.0 - other.0
24524    }
24525}
24526
24527trait RowRangeExt {
24528    type Row;
24529
24530    fn len(&self) -> usize;
24531
24532    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24533}
24534
24535impl RowRangeExt for Range<MultiBufferRow> {
24536    type Row = MultiBufferRow;
24537
24538    fn len(&self) -> usize {
24539        (self.end.0 - self.start.0) as usize
24540    }
24541
24542    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24543        (self.start.0..self.end.0).map(MultiBufferRow)
24544    }
24545}
24546
24547impl RowRangeExt for Range<DisplayRow> {
24548    type Row = DisplayRow;
24549
24550    fn len(&self) -> usize {
24551        (self.end.0 - self.start.0) as usize
24552    }
24553
24554    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24555        (self.start.0..self.end.0).map(DisplayRow)
24556    }
24557}
24558
24559/// If select range has more than one line, we
24560/// just point the cursor to range.start.
24561fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24562    if range.start.row == range.end.row {
24563        range
24564    } else {
24565        range.start..range.start
24566    }
24567}
24568pub struct KillRing(ClipboardItem);
24569impl Global for KillRing {}
24570
24571const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24572
24573enum BreakpointPromptEditAction {
24574    Log,
24575    Condition,
24576    HitCondition,
24577}
24578
24579struct BreakpointPromptEditor {
24580    pub(crate) prompt: Entity<Editor>,
24581    editor: WeakEntity<Editor>,
24582    breakpoint_anchor: Anchor,
24583    breakpoint: Breakpoint,
24584    edit_action: BreakpointPromptEditAction,
24585    block_ids: HashSet<CustomBlockId>,
24586    editor_margins: Arc<Mutex<EditorMargins>>,
24587    _subscriptions: Vec<Subscription>,
24588}
24589
24590impl BreakpointPromptEditor {
24591    const MAX_LINES: u8 = 4;
24592
24593    fn new(
24594        editor: WeakEntity<Editor>,
24595        breakpoint_anchor: Anchor,
24596        breakpoint: Breakpoint,
24597        edit_action: BreakpointPromptEditAction,
24598        window: &mut Window,
24599        cx: &mut Context<Self>,
24600    ) -> Self {
24601        let base_text = match edit_action {
24602            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24603            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24604            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24605        }
24606        .map(|msg| msg.to_string())
24607        .unwrap_or_default();
24608
24609        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24610        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24611
24612        let prompt = cx.new(|cx| {
24613            let mut prompt = Editor::new(
24614                EditorMode::AutoHeight {
24615                    min_lines: 1,
24616                    max_lines: Some(Self::MAX_LINES as usize),
24617                },
24618                buffer,
24619                None,
24620                window,
24621                cx,
24622            );
24623            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24624            prompt.set_show_cursor_when_unfocused(false, cx);
24625            prompt.set_placeholder_text(
24626                match edit_action {
24627                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24628                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24629                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24630                },
24631                window,
24632                cx,
24633            );
24634
24635            prompt
24636        });
24637
24638        Self {
24639            prompt,
24640            editor,
24641            breakpoint_anchor,
24642            breakpoint,
24643            edit_action,
24644            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24645            block_ids: Default::default(),
24646            _subscriptions: vec![],
24647        }
24648    }
24649
24650    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24651        self.block_ids.extend(block_ids)
24652    }
24653
24654    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24655        if let Some(editor) = self.editor.upgrade() {
24656            let message = self
24657                .prompt
24658                .read(cx)
24659                .buffer
24660                .read(cx)
24661                .as_singleton()
24662                .expect("A multi buffer in breakpoint prompt isn't possible")
24663                .read(cx)
24664                .as_rope()
24665                .to_string();
24666
24667            editor.update(cx, |editor, cx| {
24668                editor.edit_breakpoint_at_anchor(
24669                    self.breakpoint_anchor,
24670                    self.breakpoint.clone(),
24671                    match self.edit_action {
24672                        BreakpointPromptEditAction::Log => {
24673                            BreakpointEditAction::EditLogMessage(message.into())
24674                        }
24675                        BreakpointPromptEditAction::Condition => {
24676                            BreakpointEditAction::EditCondition(message.into())
24677                        }
24678                        BreakpointPromptEditAction::HitCondition => {
24679                            BreakpointEditAction::EditHitCondition(message.into())
24680                        }
24681                    },
24682                    cx,
24683                );
24684
24685                editor.remove_blocks(self.block_ids.clone(), None, cx);
24686                cx.focus_self(window);
24687            });
24688        }
24689    }
24690
24691    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24692        self.editor
24693            .update(cx, |editor, cx| {
24694                editor.remove_blocks(self.block_ids.clone(), None, cx);
24695                window.focus(&editor.focus_handle);
24696            })
24697            .log_err();
24698    }
24699
24700    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24701        let settings = ThemeSettings::get_global(cx);
24702        let text_style = TextStyle {
24703            color: if self.prompt.read(cx).read_only(cx) {
24704                cx.theme().colors().text_disabled
24705            } else {
24706                cx.theme().colors().text
24707            },
24708            font_family: settings.buffer_font.family.clone(),
24709            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24710            font_size: settings.buffer_font_size(cx).into(),
24711            font_weight: settings.buffer_font.weight,
24712            line_height: relative(settings.buffer_line_height.value()),
24713            ..Default::default()
24714        };
24715        EditorElement::new(
24716            &self.prompt,
24717            EditorStyle {
24718                background: cx.theme().colors().editor_background,
24719                local_player: cx.theme().players().local(),
24720                text: text_style,
24721                ..Default::default()
24722            },
24723        )
24724    }
24725}
24726
24727impl Render for BreakpointPromptEditor {
24728    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24729        let editor_margins = *self.editor_margins.lock();
24730        let gutter_dimensions = editor_margins.gutter;
24731        h_flex()
24732            .key_context("Editor")
24733            .bg(cx.theme().colors().editor_background)
24734            .border_y_1()
24735            .border_color(cx.theme().status().info_border)
24736            .size_full()
24737            .py(window.line_height() / 2.5)
24738            .on_action(cx.listener(Self::confirm))
24739            .on_action(cx.listener(Self::cancel))
24740            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24741            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24742    }
24743}
24744
24745impl Focusable for BreakpointPromptEditor {
24746    fn focus_handle(&self, cx: &App) -> FocusHandle {
24747        self.prompt.focus_handle(cx)
24748    }
24749}
24750
24751fn all_edits_insertions_or_deletions(
24752    edits: &Vec<(Range<Anchor>, String)>,
24753    snapshot: &MultiBufferSnapshot,
24754) -> bool {
24755    let mut all_insertions = true;
24756    let mut all_deletions = true;
24757
24758    for (range, new_text) in edits.iter() {
24759        let range_is_empty = range.to_offset(snapshot).is_empty();
24760        let text_is_empty = new_text.is_empty();
24761
24762        if range_is_empty != text_is_empty {
24763            if range_is_empty {
24764                all_deletions = false;
24765            } else {
24766                all_insertions = false;
24767            }
24768        } else {
24769            return false;
24770        }
24771
24772        if !all_insertions && !all_deletions {
24773            return false;
24774        }
24775    }
24776    all_insertions || all_deletions
24777}
24778
24779struct MissingEditPredictionKeybindingTooltip;
24780
24781impl Render for MissingEditPredictionKeybindingTooltip {
24782    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24783        ui::tooltip_container(cx, |container, cx| {
24784            container
24785                .flex_shrink_0()
24786                .max_w_80()
24787                .min_h(rems_from_px(124.))
24788                .justify_between()
24789                .child(
24790                    v_flex()
24791                        .flex_1()
24792                        .text_ui_sm(cx)
24793                        .child(Label::new("Conflict with Accept Keybinding"))
24794                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24795                )
24796                .child(
24797                    h_flex()
24798                        .pb_1()
24799                        .gap_1()
24800                        .items_end()
24801                        .w_full()
24802                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24803                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24804                        }))
24805                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24806                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24807                        })),
24808                )
24809        })
24810    }
24811}
24812
24813#[derive(Debug, Clone, Copy, PartialEq)]
24814pub struct LineHighlight {
24815    pub background: Background,
24816    pub border: Option<gpui::Hsla>,
24817    pub include_gutter: bool,
24818    pub type_id: Option<TypeId>,
24819}
24820
24821struct LineManipulationResult {
24822    pub new_text: String,
24823    pub line_count_before: usize,
24824    pub line_count_after: usize,
24825}
24826
24827fn render_diff_hunk_controls(
24828    row: u32,
24829    status: &DiffHunkStatus,
24830    hunk_range: Range<Anchor>,
24831    is_created_file: bool,
24832    line_height: Pixels,
24833    editor: &Entity<Editor>,
24834    _window: &mut Window,
24835    cx: &mut App,
24836) -> AnyElement {
24837    h_flex()
24838        .h(line_height)
24839        .mr_1()
24840        .gap_1()
24841        .px_0p5()
24842        .pb_1()
24843        .border_x_1()
24844        .border_b_1()
24845        .border_color(cx.theme().colors().border_variant)
24846        .rounded_b_lg()
24847        .bg(cx.theme().colors().editor_background)
24848        .gap_1()
24849        .block_mouse_except_scroll()
24850        .shadow_md()
24851        .child(if status.has_secondary_hunk() {
24852            Button::new(("stage", row as u64), "Stage")
24853                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24854                .tooltip({
24855                    let focus_handle = editor.focus_handle(cx);
24856                    move |window, cx| {
24857                        Tooltip::for_action_in(
24858                            "Stage Hunk",
24859                            &::git::ToggleStaged,
24860                            &focus_handle,
24861                            window,
24862                            cx,
24863                        )
24864                    }
24865                })
24866                .on_click({
24867                    let editor = editor.clone();
24868                    move |_event, _window, cx| {
24869                        editor.update(cx, |editor, cx| {
24870                            editor.stage_or_unstage_diff_hunks(
24871                                true,
24872                                vec![hunk_range.start..hunk_range.start],
24873                                cx,
24874                            );
24875                        });
24876                    }
24877                })
24878        } else {
24879            Button::new(("unstage", row as u64), "Unstage")
24880                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24881                .tooltip({
24882                    let focus_handle = editor.focus_handle(cx);
24883                    move |window, cx| {
24884                        Tooltip::for_action_in(
24885                            "Unstage Hunk",
24886                            &::git::ToggleStaged,
24887                            &focus_handle,
24888                            window,
24889                            cx,
24890                        )
24891                    }
24892                })
24893                .on_click({
24894                    let editor = editor.clone();
24895                    move |_event, _window, cx| {
24896                        editor.update(cx, |editor, cx| {
24897                            editor.stage_or_unstage_diff_hunks(
24898                                false,
24899                                vec![hunk_range.start..hunk_range.start],
24900                                cx,
24901                            );
24902                        });
24903                    }
24904                })
24905        })
24906        .child(
24907            Button::new(("restore", row as u64), "Restore")
24908                .tooltip({
24909                    let focus_handle = editor.focus_handle(cx);
24910                    move |window, cx| {
24911                        Tooltip::for_action_in(
24912                            "Restore Hunk",
24913                            &::git::Restore,
24914                            &focus_handle,
24915                            window,
24916                            cx,
24917                        )
24918                    }
24919                })
24920                .on_click({
24921                    let editor = editor.clone();
24922                    move |_event, window, cx| {
24923                        editor.update(cx, |editor, cx| {
24924                            let snapshot = editor.snapshot(window, cx);
24925                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24926                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24927                        });
24928                    }
24929                })
24930                .disabled(is_created_file),
24931        )
24932        .when(
24933            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24934            |el| {
24935                el.child(
24936                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24937                        .shape(IconButtonShape::Square)
24938                        .icon_size(IconSize::Small)
24939                        // .disabled(!has_multiple_hunks)
24940                        .tooltip({
24941                            let focus_handle = editor.focus_handle(cx);
24942                            move |window, cx| {
24943                                Tooltip::for_action_in(
24944                                    "Next Hunk",
24945                                    &GoToHunk,
24946                                    &focus_handle,
24947                                    window,
24948                                    cx,
24949                                )
24950                            }
24951                        })
24952                        .on_click({
24953                            let editor = editor.clone();
24954                            move |_event, window, cx| {
24955                                editor.update(cx, |editor, cx| {
24956                                    let snapshot = editor.snapshot(window, cx);
24957                                    let position =
24958                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24959                                    editor.go_to_hunk_before_or_after_position(
24960                                        &snapshot,
24961                                        position,
24962                                        Direction::Next,
24963                                        window,
24964                                        cx,
24965                                    );
24966                                    editor.expand_selected_diff_hunks(cx);
24967                                });
24968                            }
24969                        }),
24970                )
24971                .child(
24972                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24973                        .shape(IconButtonShape::Square)
24974                        .icon_size(IconSize::Small)
24975                        // .disabled(!has_multiple_hunks)
24976                        .tooltip({
24977                            let focus_handle = editor.focus_handle(cx);
24978                            move |window, cx| {
24979                                Tooltip::for_action_in(
24980                                    "Previous Hunk",
24981                                    &GoToPreviousHunk,
24982                                    &focus_handle,
24983                                    window,
24984                                    cx,
24985                                )
24986                            }
24987                        })
24988                        .on_click({
24989                            let editor = editor.clone();
24990                            move |_event, window, cx| {
24991                                editor.update(cx, |editor, cx| {
24992                                    let snapshot = editor.snapshot(window, cx);
24993                                    let point =
24994                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24995                                    editor.go_to_hunk_before_or_after_position(
24996                                        &snapshot,
24997                                        point,
24998                                        Direction::Prev,
24999                                        window,
25000                                        cx,
25001                                    );
25002                                    editor.expand_selected_diff_hunks(cx);
25003                                });
25004                            }
25005                        }),
25006                )
25007            },
25008        )
25009        .into_any_element()
25010}
25011
25012pub fn multibuffer_context_lines(cx: &App) -> u32 {
25013    EditorSettings::try_get(cx)
25014        .map(|settings| settings.excerpt_context_lines)
25015        .unwrap_or(2)
25016        .min(32)
25017}