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: &mut Window, cx: &mut 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: &mut Window,
 2477        cx: &mut 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        let disjoint = self.selections.disjoint_anchors();
 2555        let snapshot = self.snapshot(window, cx);
 2556        let snapshot = snapshot.buffer_snapshot();
 2557        if self.mode == EditorMode::SingleLine
 2558            && let [selection] = disjoint
 2559            && selection.start == selection.end
 2560            && selection.end.to_offset(snapshot) == snapshot.len()
 2561        {
 2562            key_context.add("end_of_input");
 2563        }
 2564
 2565        key_context
 2566    }
 2567
 2568    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2569        self.last_bounds.as_ref()
 2570    }
 2571
 2572    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2573        if self.mouse_cursor_hidden {
 2574            self.mouse_cursor_hidden = false;
 2575            cx.notify();
 2576        }
 2577    }
 2578
 2579    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2580        let hide_mouse_cursor = match origin {
 2581            HideMouseCursorOrigin::TypingAction => {
 2582                matches!(
 2583                    self.hide_mouse_mode,
 2584                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2585                )
 2586            }
 2587            HideMouseCursorOrigin::MovementAction => {
 2588                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2589            }
 2590        };
 2591        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2592            self.mouse_cursor_hidden = hide_mouse_cursor;
 2593            cx.notify();
 2594        }
 2595    }
 2596
 2597    pub fn edit_prediction_in_conflict(&self) -> bool {
 2598        if !self.show_edit_predictions_in_menu() {
 2599            return false;
 2600        }
 2601
 2602        let showing_completions = self
 2603            .context_menu
 2604            .borrow()
 2605            .as_ref()
 2606            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2607
 2608        showing_completions
 2609            || self.edit_prediction_requires_modifier()
 2610            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2611            // bindings to insert tab characters.
 2612            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2613    }
 2614
 2615    pub fn accept_edit_prediction_keybind(
 2616        &self,
 2617        accept_partial: bool,
 2618        window: &mut Window,
 2619        cx: &mut App,
 2620    ) -> AcceptEditPredictionBinding {
 2621        let key_context = self.key_context_internal(true, window, cx);
 2622        let in_conflict = self.edit_prediction_in_conflict();
 2623
 2624        let bindings = if accept_partial {
 2625            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2626        } else {
 2627            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2628        };
 2629
 2630        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2631        // just the first one.
 2632        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2633            !in_conflict
 2634                || binding
 2635                    .keystrokes()
 2636                    .first()
 2637                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2638        }))
 2639    }
 2640
 2641    pub fn new_file(
 2642        workspace: &mut Workspace,
 2643        _: &workspace::NewFile,
 2644        window: &mut Window,
 2645        cx: &mut Context<Workspace>,
 2646    ) {
 2647        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2648            "Failed to create buffer",
 2649            window,
 2650            cx,
 2651            |e, _, _| match e.error_code() {
 2652                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2653                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2654                e.error_tag("required").unwrap_or("the latest version")
 2655            )),
 2656                _ => None,
 2657            },
 2658        );
 2659    }
 2660
 2661    pub fn new_in_workspace(
 2662        workspace: &mut Workspace,
 2663        window: &mut Window,
 2664        cx: &mut Context<Workspace>,
 2665    ) -> Task<Result<Entity<Editor>>> {
 2666        let project = workspace.project().clone();
 2667        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2668
 2669        cx.spawn_in(window, async move |workspace, cx| {
 2670            let buffer = create.await?;
 2671            workspace.update_in(cx, |workspace, window, cx| {
 2672                let editor =
 2673                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2674                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2675                editor
 2676            })
 2677        })
 2678    }
 2679
 2680    fn new_file_vertical(
 2681        workspace: &mut Workspace,
 2682        _: &workspace::NewFileSplitVertical,
 2683        window: &mut Window,
 2684        cx: &mut Context<Workspace>,
 2685    ) {
 2686        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2687    }
 2688
 2689    fn new_file_horizontal(
 2690        workspace: &mut Workspace,
 2691        _: &workspace::NewFileSplitHorizontal,
 2692        window: &mut Window,
 2693        cx: &mut Context<Workspace>,
 2694    ) {
 2695        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2696    }
 2697
 2698    fn new_file_split(
 2699        workspace: &mut Workspace,
 2700        action: &workspace::NewFileSplit,
 2701        window: &mut Window,
 2702        cx: &mut Context<Workspace>,
 2703    ) {
 2704        Self::new_file_in_direction(workspace, action.0, window, cx)
 2705    }
 2706
 2707    fn new_file_in_direction(
 2708        workspace: &mut Workspace,
 2709        direction: SplitDirection,
 2710        window: &mut Window,
 2711        cx: &mut Context<Workspace>,
 2712    ) {
 2713        let project = workspace.project().clone();
 2714        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2715
 2716        cx.spawn_in(window, async move |workspace, cx| {
 2717            let buffer = create.await?;
 2718            workspace.update_in(cx, move |workspace, window, cx| {
 2719                workspace.split_item(
 2720                    direction,
 2721                    Box::new(
 2722                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2723                    ),
 2724                    window,
 2725                    cx,
 2726                )
 2727            })?;
 2728            anyhow::Ok(())
 2729        })
 2730        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2731            match e.error_code() {
 2732                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2733                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2734                e.error_tag("required").unwrap_or("the latest version")
 2735            )),
 2736                _ => None,
 2737            }
 2738        });
 2739    }
 2740
 2741    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2742        self.leader_id
 2743    }
 2744
 2745    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2746        &self.buffer
 2747    }
 2748
 2749    pub fn project(&self) -> Option<&Entity<Project>> {
 2750        self.project.as_ref()
 2751    }
 2752
 2753    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2754        self.workspace.as_ref()?.0.upgrade()
 2755    }
 2756
 2757    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2758        self.buffer().read(cx).title(cx)
 2759    }
 2760
 2761    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2762        let git_blame_gutter_max_author_length = self
 2763            .render_git_blame_gutter(cx)
 2764            .then(|| {
 2765                if let Some(blame) = self.blame.as_ref() {
 2766                    let max_author_length =
 2767                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2768                    Some(max_author_length)
 2769                } else {
 2770                    None
 2771                }
 2772            })
 2773            .flatten();
 2774
 2775        EditorSnapshot {
 2776            mode: self.mode.clone(),
 2777            show_gutter: self.show_gutter,
 2778            show_line_numbers: self.show_line_numbers,
 2779            show_git_diff_gutter: self.show_git_diff_gutter,
 2780            show_code_actions: self.show_code_actions,
 2781            show_runnables: self.show_runnables,
 2782            show_breakpoints: self.show_breakpoints,
 2783            git_blame_gutter_max_author_length,
 2784            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2785            placeholder_display_snapshot: self
 2786                .placeholder_display_map
 2787                .as_ref()
 2788                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2789            scroll_anchor: self.scroll_manager.anchor(),
 2790            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2791            is_focused: self.focus_handle.is_focused(window),
 2792            current_line_highlight: self
 2793                .current_line_highlight
 2794                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2795            gutter_hovered: self.gutter_hovered,
 2796        }
 2797    }
 2798
 2799    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2800        self.buffer.read(cx).language_at(point, cx)
 2801    }
 2802
 2803    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2804        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2805    }
 2806
 2807    pub fn active_excerpt(
 2808        &self,
 2809        cx: &App,
 2810    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2811        self.buffer
 2812            .read(cx)
 2813            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2814    }
 2815
 2816    pub fn mode(&self) -> &EditorMode {
 2817        &self.mode
 2818    }
 2819
 2820    pub fn set_mode(&mut self, mode: EditorMode) {
 2821        self.mode = mode;
 2822    }
 2823
 2824    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2825        self.collaboration_hub.as_deref()
 2826    }
 2827
 2828    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2829        self.collaboration_hub = Some(hub);
 2830    }
 2831
 2832    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2833        self.in_project_search = in_project_search;
 2834    }
 2835
 2836    pub fn set_custom_context_menu(
 2837        &mut self,
 2838        f: impl 'static
 2839        + Fn(
 2840            &mut Self,
 2841            DisplayPoint,
 2842            &mut Window,
 2843            &mut Context<Self>,
 2844        ) -> Option<Entity<ui::ContextMenu>>,
 2845    ) {
 2846        self.custom_context_menu = Some(Box::new(f))
 2847    }
 2848
 2849    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2850        self.completion_provider = provider;
 2851    }
 2852
 2853    #[cfg(any(test, feature = "test-support"))]
 2854    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2855        self.completion_provider.clone()
 2856    }
 2857
 2858    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2859        self.semantics_provider.clone()
 2860    }
 2861
 2862    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2863        self.semantics_provider = provider;
 2864    }
 2865
 2866    pub fn set_edit_prediction_provider<T>(
 2867        &mut self,
 2868        provider: Option<Entity<T>>,
 2869        window: &mut Window,
 2870        cx: &mut Context<Self>,
 2871    ) where
 2872        T: EditPredictionProvider,
 2873    {
 2874        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2875            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2876                if this.focus_handle.is_focused(window) {
 2877                    this.update_visible_edit_prediction(window, cx);
 2878                }
 2879            }),
 2880            provider: Arc::new(provider),
 2881        });
 2882        self.update_edit_prediction_settings(cx);
 2883        self.refresh_edit_prediction(false, false, window, cx);
 2884    }
 2885
 2886    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2887        self.placeholder_display_map
 2888            .as_ref()
 2889            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2890    }
 2891
 2892    pub fn set_placeholder_text(
 2893        &mut self,
 2894        placeholder_text: &str,
 2895        window: &mut Window,
 2896        cx: &mut Context<Self>,
 2897    ) {
 2898        let multibuffer = cx
 2899            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2900
 2901        let style = window.text_style();
 2902
 2903        self.placeholder_display_map = Some(cx.new(|cx| {
 2904            DisplayMap::new(
 2905                multibuffer,
 2906                style.font(),
 2907                style.font_size.to_pixels(window.rem_size()),
 2908                None,
 2909                FILE_HEADER_HEIGHT,
 2910                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2911                Default::default(),
 2912                DiagnosticSeverity::Off,
 2913                cx,
 2914            )
 2915        }));
 2916        cx.notify();
 2917    }
 2918
 2919    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2920        self.cursor_shape = cursor_shape;
 2921
 2922        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2923        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2924
 2925        cx.notify();
 2926    }
 2927
 2928    pub fn set_current_line_highlight(
 2929        &mut self,
 2930        current_line_highlight: Option<CurrentLineHighlight>,
 2931    ) {
 2932        self.current_line_highlight = current_line_highlight;
 2933    }
 2934
 2935    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2936        self.collapse_matches = collapse_matches;
 2937    }
 2938
 2939    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2940        if self.collapse_matches {
 2941            return range.start..range.start;
 2942        }
 2943        range.clone()
 2944    }
 2945
 2946    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2947        if self.display_map.read(cx).clip_at_line_ends != clip {
 2948            self.display_map
 2949                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2950        }
 2951    }
 2952
 2953    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2954        self.input_enabled = input_enabled;
 2955    }
 2956
 2957    pub fn set_edit_predictions_hidden_for_vim_mode(
 2958        &mut self,
 2959        hidden: bool,
 2960        window: &mut Window,
 2961        cx: &mut Context<Self>,
 2962    ) {
 2963        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2964            self.edit_predictions_hidden_for_vim_mode = hidden;
 2965            if hidden {
 2966                self.update_visible_edit_prediction(window, cx);
 2967            } else {
 2968                self.refresh_edit_prediction(true, false, window, cx);
 2969            }
 2970        }
 2971    }
 2972
 2973    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2974        self.menu_edit_predictions_policy = value;
 2975    }
 2976
 2977    pub fn set_autoindent(&mut self, autoindent: bool) {
 2978        if autoindent {
 2979            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2980        } else {
 2981            self.autoindent_mode = None;
 2982        }
 2983    }
 2984
 2985    pub fn read_only(&self, cx: &App) -> bool {
 2986        self.read_only || self.buffer.read(cx).read_only()
 2987    }
 2988
 2989    pub fn set_read_only(&mut self, read_only: bool) {
 2990        self.read_only = read_only;
 2991    }
 2992
 2993    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2994        self.use_autoclose = autoclose;
 2995    }
 2996
 2997    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2998        self.use_auto_surround = auto_surround;
 2999    }
 3000
 3001    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3002        self.auto_replace_emoji_shortcode = auto_replace;
 3003    }
 3004
 3005    pub fn toggle_edit_predictions(
 3006        &mut self,
 3007        _: &ToggleEditPrediction,
 3008        window: &mut Window,
 3009        cx: &mut Context<Self>,
 3010    ) {
 3011        if self.show_edit_predictions_override.is_some() {
 3012            self.set_show_edit_predictions(None, window, cx);
 3013        } else {
 3014            let show_edit_predictions = !self.edit_predictions_enabled();
 3015            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3016        }
 3017    }
 3018
 3019    pub fn set_show_edit_predictions(
 3020        &mut self,
 3021        show_edit_predictions: Option<bool>,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024    ) {
 3025        self.show_edit_predictions_override = show_edit_predictions;
 3026        self.update_edit_prediction_settings(cx);
 3027
 3028        if let Some(false) = show_edit_predictions {
 3029            self.discard_edit_prediction(false, cx);
 3030        } else {
 3031            self.refresh_edit_prediction(false, true, window, cx);
 3032        }
 3033    }
 3034
 3035    fn edit_predictions_disabled_in_scope(
 3036        &self,
 3037        buffer: &Entity<Buffer>,
 3038        buffer_position: language::Anchor,
 3039        cx: &App,
 3040    ) -> bool {
 3041        let snapshot = buffer.read(cx).snapshot();
 3042        let settings = snapshot.settings_at(buffer_position, cx);
 3043
 3044        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3045            return false;
 3046        };
 3047
 3048        scope.override_name().is_some_and(|scope_name| {
 3049            settings
 3050                .edit_predictions_disabled_in
 3051                .iter()
 3052                .any(|s| s == scope_name)
 3053        })
 3054    }
 3055
 3056    pub fn set_use_modal_editing(&mut self, to: bool) {
 3057        self.use_modal_editing = to;
 3058    }
 3059
 3060    pub fn use_modal_editing(&self) -> bool {
 3061        self.use_modal_editing
 3062    }
 3063
 3064    fn selections_did_change(
 3065        &mut self,
 3066        local: bool,
 3067        old_cursor_position: &Anchor,
 3068        effects: SelectionEffects,
 3069        window: &mut Window,
 3070        cx: &mut Context<Self>,
 3071    ) {
 3072        window.invalidate_character_coordinates();
 3073
 3074        // Copy selections to primary selection buffer
 3075        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3076        if local {
 3077            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3078            let buffer_handle = self.buffer.read(cx).read(cx);
 3079
 3080            let mut text = String::new();
 3081            for (index, selection) in selections.iter().enumerate() {
 3082                let text_for_selection = buffer_handle
 3083                    .text_for_range(selection.start..selection.end)
 3084                    .collect::<String>();
 3085
 3086                text.push_str(&text_for_selection);
 3087                if index != selections.len() - 1 {
 3088                    text.push('\n');
 3089                }
 3090            }
 3091
 3092            if !text.is_empty() {
 3093                cx.write_to_primary(ClipboardItem::new_string(text));
 3094            }
 3095        }
 3096
 3097        let selection_anchors = self.selections.disjoint_anchors_arc();
 3098
 3099        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3100            self.buffer.update(cx, |buffer, cx| {
 3101                buffer.set_active_selections(
 3102                    &selection_anchors,
 3103                    self.selections.line_mode(),
 3104                    self.cursor_shape,
 3105                    cx,
 3106                )
 3107            });
 3108        }
 3109        let display_map = self
 3110            .display_map
 3111            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3112        let buffer = display_map.buffer_snapshot();
 3113        if self.selections.count() == 1 {
 3114            self.add_selections_state = None;
 3115        }
 3116        self.select_next_state = None;
 3117        self.select_prev_state = None;
 3118        self.select_syntax_node_history.try_clear();
 3119        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3120        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3121        self.take_rename(false, window, cx);
 3122
 3123        let newest_selection = self.selections.newest_anchor();
 3124        let new_cursor_position = newest_selection.head();
 3125        let selection_start = newest_selection.start;
 3126
 3127        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3128            self.push_to_nav_history(
 3129                *old_cursor_position,
 3130                Some(new_cursor_position.to_point(buffer)),
 3131                false,
 3132                effects.nav_history == Some(true),
 3133                cx,
 3134            );
 3135        }
 3136
 3137        if local {
 3138            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3139                self.register_buffer(buffer_id, cx);
 3140            }
 3141
 3142            let mut context_menu = self.context_menu.borrow_mut();
 3143            let completion_menu = match context_menu.as_ref() {
 3144                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3145                Some(CodeContextMenu::CodeActions(_)) => {
 3146                    *context_menu = None;
 3147                    None
 3148                }
 3149                None => None,
 3150            };
 3151            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3152            drop(context_menu);
 3153
 3154            if effects.completions
 3155                && let Some(completion_position) = completion_position
 3156            {
 3157                let start_offset = selection_start.to_offset(buffer);
 3158                let position_matches = start_offset == completion_position.to_offset(buffer);
 3159                let continue_showing = if position_matches {
 3160                    if self.snippet_stack.is_empty() {
 3161                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3162                            == Some(CharKind::Word)
 3163                    } else {
 3164                        // Snippet choices can be shown even when the cursor is in whitespace.
 3165                        // Dismissing the menu with actions like backspace is handled by
 3166                        // invalidation regions.
 3167                        true
 3168                    }
 3169                } else {
 3170                    false
 3171                };
 3172
 3173                if continue_showing {
 3174                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3175                } else {
 3176                    self.hide_context_menu(window, cx);
 3177                }
 3178            }
 3179
 3180            hide_hover(self, cx);
 3181
 3182            if old_cursor_position.to_display_point(&display_map).row()
 3183                != new_cursor_position.to_display_point(&display_map).row()
 3184            {
 3185                self.available_code_actions.take();
 3186            }
 3187            self.refresh_code_actions(window, cx);
 3188            self.refresh_document_highlights(cx);
 3189            refresh_linked_ranges(self, window, cx);
 3190
 3191            self.refresh_selected_text_highlights(false, window, cx);
 3192            refresh_matching_bracket_highlights(self, cx);
 3193            self.update_visible_edit_prediction(window, cx);
 3194            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3195            self.inline_blame_popover.take();
 3196            if self.git_blame_inline_enabled {
 3197                self.start_inline_blame_timer(window, cx);
 3198            }
 3199        }
 3200
 3201        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3202        cx.emit(EditorEvent::SelectionsChanged { local });
 3203
 3204        let selections = &self.selections.disjoint_anchors_arc();
 3205        if selections.len() == 1 {
 3206            cx.emit(SearchEvent::ActiveMatchChanged)
 3207        }
 3208        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3209            let inmemory_selections = selections
 3210                .iter()
 3211                .map(|s| {
 3212                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3213                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3214                })
 3215                .collect();
 3216            self.update_restoration_data(cx, |data| {
 3217                data.selections = inmemory_selections;
 3218            });
 3219
 3220            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3221                && let Some(workspace_id) =
 3222                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3223            {
 3224                let snapshot = self.buffer().read(cx).snapshot(cx);
 3225                let selections = selections.clone();
 3226                let background_executor = cx.background_executor().clone();
 3227                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3228                self.serialize_selections = cx.background_spawn(async move {
 3229                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3230                    let db_selections = selections
 3231                        .iter()
 3232                        .map(|selection| {
 3233                            (
 3234                                selection.start.to_offset(&snapshot),
 3235                                selection.end.to_offset(&snapshot),
 3236                            )
 3237                        })
 3238                        .collect();
 3239
 3240                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3241                        .await
 3242                        .with_context(|| {
 3243                            format!(
 3244                                "persisting editor selections for editor {editor_id}, \
 3245                                workspace {workspace_id:?}"
 3246                            )
 3247                        })
 3248                        .log_err();
 3249                });
 3250            }
 3251        }
 3252
 3253        cx.notify();
 3254    }
 3255
 3256    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3257        use text::ToOffset as _;
 3258        use text::ToPoint as _;
 3259
 3260        if self.mode.is_minimap()
 3261            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3262        {
 3263            return;
 3264        }
 3265
 3266        if !self.buffer().read(cx).is_singleton() {
 3267            return;
 3268        }
 3269
 3270        let display_snapshot = self
 3271            .display_map
 3272            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3273        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3274            return;
 3275        };
 3276        let inmemory_folds = display_snapshot
 3277            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3278            .map(|fold| {
 3279                fold.range.start.text_anchor.to_point(&snapshot)
 3280                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3281            })
 3282            .collect();
 3283        self.update_restoration_data(cx, |data| {
 3284            data.folds = inmemory_folds;
 3285        });
 3286
 3287        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3288            return;
 3289        };
 3290        let background_executor = cx.background_executor().clone();
 3291        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3292        let db_folds = display_snapshot
 3293            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3294            .map(|fold| {
 3295                (
 3296                    fold.range.start.text_anchor.to_offset(&snapshot),
 3297                    fold.range.end.text_anchor.to_offset(&snapshot),
 3298                )
 3299            })
 3300            .collect();
 3301        self.serialize_folds = cx.background_spawn(async move {
 3302            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3303            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3304                .await
 3305                .with_context(|| {
 3306                    format!(
 3307                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3308                    )
 3309                })
 3310                .log_err();
 3311        });
 3312    }
 3313
 3314    pub fn sync_selections(
 3315        &mut self,
 3316        other: Entity<Editor>,
 3317        cx: &mut Context<Self>,
 3318    ) -> gpui::Subscription {
 3319        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3320        if !other_selections.is_empty() {
 3321            self.selections.change_with(cx, |selections| {
 3322                selections.select_anchors(other_selections);
 3323            });
 3324        }
 3325
 3326        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3327            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3328                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3329                if other_selections.is_empty() {
 3330                    return;
 3331                }
 3332                this.selections.change_with(cx, |selections| {
 3333                    selections.select_anchors(other_selections);
 3334                });
 3335            }
 3336        });
 3337
 3338        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3339            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3340                let these_selections = this.selections.disjoint_anchors().to_vec();
 3341                if these_selections.is_empty() {
 3342                    return;
 3343                }
 3344                other.update(cx, |other_editor, cx| {
 3345                    other_editor.selections.change_with(cx, |selections| {
 3346                        selections.select_anchors(these_selections);
 3347                    })
 3348                });
 3349            }
 3350        });
 3351
 3352        Subscription::join(other_subscription, this_subscription)
 3353    }
 3354
 3355    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3356    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3357    /// effects of selection change occur at the end of the transaction.
 3358    pub fn change_selections<R>(
 3359        &mut self,
 3360        effects: SelectionEffects,
 3361        window: &mut Window,
 3362        cx: &mut Context<Self>,
 3363        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3364    ) -> R {
 3365        if let Some(state) = &mut self.deferred_selection_effects_state {
 3366            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3367            state.effects.completions = effects.completions;
 3368            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3369            let (changed, result) = self.selections.change_with(cx, change);
 3370            state.changed |= changed;
 3371            return result;
 3372        }
 3373        let mut state = DeferredSelectionEffectsState {
 3374            changed: false,
 3375            effects,
 3376            old_cursor_position: self.selections.newest_anchor().head(),
 3377            history_entry: SelectionHistoryEntry {
 3378                selections: self.selections.disjoint_anchors_arc(),
 3379                select_next_state: self.select_next_state.clone(),
 3380                select_prev_state: self.select_prev_state.clone(),
 3381                add_selections_state: self.add_selections_state.clone(),
 3382            },
 3383        };
 3384        let (changed, result) = self.selections.change_with(cx, change);
 3385        state.changed = state.changed || changed;
 3386        if self.defer_selection_effects {
 3387            self.deferred_selection_effects_state = Some(state);
 3388        } else {
 3389            self.apply_selection_effects(state, window, cx);
 3390        }
 3391        result
 3392    }
 3393
 3394    /// Defers the effects of selection change, so that the effects of multiple calls to
 3395    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3396    /// to selection history and the state of popovers based on selection position aren't
 3397    /// erroneously updated.
 3398    pub fn with_selection_effects_deferred<R>(
 3399        &mut self,
 3400        window: &mut Window,
 3401        cx: &mut Context<Self>,
 3402        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3403    ) -> R {
 3404        let already_deferred = self.defer_selection_effects;
 3405        self.defer_selection_effects = true;
 3406        let result = update(self, window, cx);
 3407        if !already_deferred {
 3408            self.defer_selection_effects = false;
 3409            if let Some(state) = self.deferred_selection_effects_state.take() {
 3410                self.apply_selection_effects(state, window, cx);
 3411            }
 3412        }
 3413        result
 3414    }
 3415
 3416    fn apply_selection_effects(
 3417        &mut self,
 3418        state: DeferredSelectionEffectsState,
 3419        window: &mut Window,
 3420        cx: &mut Context<Self>,
 3421    ) {
 3422        if state.changed {
 3423            self.selection_history.push(state.history_entry);
 3424
 3425            if let Some(autoscroll) = state.effects.scroll {
 3426                self.request_autoscroll(autoscroll, cx);
 3427            }
 3428
 3429            let old_cursor_position = &state.old_cursor_position;
 3430
 3431            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3432
 3433            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3434                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3435            }
 3436        }
 3437    }
 3438
 3439    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3440    where
 3441        I: IntoIterator<Item = (Range<S>, T)>,
 3442        S: ToOffset,
 3443        T: Into<Arc<str>>,
 3444    {
 3445        if self.read_only(cx) {
 3446            return;
 3447        }
 3448
 3449        self.buffer
 3450            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3451    }
 3452
 3453    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3454    where
 3455        I: IntoIterator<Item = (Range<S>, T)>,
 3456        S: ToOffset,
 3457        T: Into<Arc<str>>,
 3458    {
 3459        if self.read_only(cx) {
 3460            return;
 3461        }
 3462
 3463        self.buffer.update(cx, |buffer, cx| {
 3464            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3465        });
 3466    }
 3467
 3468    pub fn edit_with_block_indent<I, S, T>(
 3469        &mut self,
 3470        edits: I,
 3471        original_indent_columns: Vec<Option<u32>>,
 3472        cx: &mut Context<Self>,
 3473    ) where
 3474        I: IntoIterator<Item = (Range<S>, T)>,
 3475        S: ToOffset,
 3476        T: Into<Arc<str>>,
 3477    {
 3478        if self.read_only(cx) {
 3479            return;
 3480        }
 3481
 3482        self.buffer.update(cx, |buffer, cx| {
 3483            buffer.edit(
 3484                edits,
 3485                Some(AutoindentMode::Block {
 3486                    original_indent_columns,
 3487                }),
 3488                cx,
 3489            )
 3490        });
 3491    }
 3492
 3493    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3494        self.hide_context_menu(window, cx);
 3495
 3496        match phase {
 3497            SelectPhase::Begin {
 3498                position,
 3499                add,
 3500                click_count,
 3501            } => self.begin_selection(position, add, click_count, window, cx),
 3502            SelectPhase::BeginColumnar {
 3503                position,
 3504                goal_column,
 3505                reset,
 3506                mode,
 3507            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3508            SelectPhase::Extend {
 3509                position,
 3510                click_count,
 3511            } => self.extend_selection(position, click_count, window, cx),
 3512            SelectPhase::Update {
 3513                position,
 3514                goal_column,
 3515                scroll_delta,
 3516            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3517            SelectPhase::End => self.end_selection(window, cx),
 3518        }
 3519    }
 3520
 3521    fn extend_selection(
 3522        &mut self,
 3523        position: DisplayPoint,
 3524        click_count: usize,
 3525        window: &mut Window,
 3526        cx: &mut Context<Self>,
 3527    ) {
 3528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3529        let tail = self.selections.newest::<usize>(&display_map).tail();
 3530        let click_count = click_count.max(match self.selections.select_mode() {
 3531            SelectMode::Character => 1,
 3532            SelectMode::Word(_) => 2,
 3533            SelectMode::Line(_) => 3,
 3534            SelectMode::All => 4,
 3535        });
 3536        self.begin_selection(position, false, click_count, window, cx);
 3537
 3538        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3539
 3540        let current_selection = match self.selections.select_mode() {
 3541            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3542            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3543        };
 3544
 3545        let mut pending_selection = self
 3546            .selections
 3547            .pending_anchor()
 3548            .cloned()
 3549            .expect("extend_selection not called with pending selection");
 3550
 3551        if pending_selection
 3552            .start
 3553            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3554            == Ordering::Greater
 3555        {
 3556            pending_selection.start = current_selection.start;
 3557        }
 3558        if pending_selection
 3559            .end
 3560            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3561            == Ordering::Less
 3562        {
 3563            pending_selection.end = current_selection.end;
 3564            pending_selection.reversed = true;
 3565        }
 3566
 3567        let mut pending_mode = self.selections.pending_mode().unwrap();
 3568        match &mut pending_mode {
 3569            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3570            _ => {}
 3571        }
 3572
 3573        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3574            SelectionEffects::scroll(Autoscroll::fit())
 3575        } else {
 3576            SelectionEffects::no_scroll()
 3577        };
 3578
 3579        self.change_selections(effects, window, cx, |s| {
 3580            s.set_pending(pending_selection.clone(), pending_mode);
 3581            s.set_is_extending(true);
 3582        });
 3583    }
 3584
 3585    fn begin_selection(
 3586        &mut self,
 3587        position: DisplayPoint,
 3588        add: bool,
 3589        click_count: usize,
 3590        window: &mut Window,
 3591        cx: &mut Context<Self>,
 3592    ) {
 3593        if !self.focus_handle.is_focused(window) {
 3594            self.last_focused_descendant = None;
 3595            window.focus(&self.focus_handle);
 3596        }
 3597
 3598        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3599        let buffer = display_map.buffer_snapshot();
 3600        let position = display_map.clip_point(position, Bias::Left);
 3601
 3602        let start;
 3603        let end;
 3604        let mode;
 3605        let mut auto_scroll;
 3606        match click_count {
 3607            1 => {
 3608                start = buffer.anchor_before(position.to_point(&display_map));
 3609                end = start;
 3610                mode = SelectMode::Character;
 3611                auto_scroll = true;
 3612            }
 3613            2 => {
 3614                let position = display_map
 3615                    .clip_point(position, Bias::Left)
 3616                    .to_offset(&display_map, Bias::Left);
 3617                let (range, _) = buffer.surrounding_word(position, None);
 3618                start = buffer.anchor_before(range.start);
 3619                end = buffer.anchor_before(range.end);
 3620                mode = SelectMode::Word(start..end);
 3621                auto_scroll = true;
 3622            }
 3623            3 => {
 3624                let position = display_map
 3625                    .clip_point(position, Bias::Left)
 3626                    .to_point(&display_map);
 3627                let line_start = display_map.prev_line_boundary(position).0;
 3628                let next_line_start = buffer.clip_point(
 3629                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3630                    Bias::Left,
 3631                );
 3632                start = buffer.anchor_before(line_start);
 3633                end = buffer.anchor_before(next_line_start);
 3634                mode = SelectMode::Line(start..end);
 3635                auto_scroll = true;
 3636            }
 3637            _ => {
 3638                start = buffer.anchor_before(0);
 3639                end = buffer.anchor_before(buffer.len());
 3640                mode = SelectMode::All;
 3641                auto_scroll = false;
 3642            }
 3643        }
 3644        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3645
 3646        let point_to_delete: Option<usize> = {
 3647            let selected_points: Vec<Selection<Point>> =
 3648                self.selections.disjoint_in_range(start..end, &display_map);
 3649
 3650            if !add || click_count > 1 {
 3651                None
 3652            } else if !selected_points.is_empty() {
 3653                Some(selected_points[0].id)
 3654            } else {
 3655                let clicked_point_already_selected =
 3656                    self.selections.disjoint_anchors().iter().find(|selection| {
 3657                        selection.start.to_point(buffer) == start.to_point(buffer)
 3658                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3659                    });
 3660
 3661                clicked_point_already_selected.map(|selection| selection.id)
 3662            }
 3663        };
 3664
 3665        let selections_count = self.selections.count();
 3666        let effects = if auto_scroll {
 3667            SelectionEffects::default()
 3668        } else {
 3669            SelectionEffects::no_scroll()
 3670        };
 3671
 3672        self.change_selections(effects, window, cx, |s| {
 3673            if let Some(point_to_delete) = point_to_delete {
 3674                s.delete(point_to_delete);
 3675
 3676                if selections_count == 1 {
 3677                    s.set_pending_anchor_range(start..end, mode);
 3678                }
 3679            } else {
 3680                if !add {
 3681                    s.clear_disjoint();
 3682                }
 3683
 3684                s.set_pending_anchor_range(start..end, mode);
 3685            }
 3686        });
 3687    }
 3688
 3689    fn begin_columnar_selection(
 3690        &mut self,
 3691        position: DisplayPoint,
 3692        goal_column: u32,
 3693        reset: bool,
 3694        mode: ColumnarMode,
 3695        window: &mut Window,
 3696        cx: &mut Context<Self>,
 3697    ) {
 3698        if !self.focus_handle.is_focused(window) {
 3699            self.last_focused_descendant = None;
 3700            window.focus(&self.focus_handle);
 3701        }
 3702
 3703        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3704
 3705        if reset {
 3706            let pointer_position = display_map
 3707                .buffer_snapshot()
 3708                .anchor_before(position.to_point(&display_map));
 3709
 3710            self.change_selections(
 3711                SelectionEffects::scroll(Autoscroll::newest()),
 3712                window,
 3713                cx,
 3714                |s| {
 3715                    s.clear_disjoint();
 3716                    s.set_pending_anchor_range(
 3717                        pointer_position..pointer_position,
 3718                        SelectMode::Character,
 3719                    );
 3720                },
 3721            );
 3722        };
 3723
 3724        let tail = self.selections.newest::<Point>(&display_map).tail();
 3725        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3726        self.columnar_selection_state = match mode {
 3727            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3728                selection_tail: selection_anchor,
 3729                display_point: if reset {
 3730                    if position.column() != goal_column {
 3731                        Some(DisplayPoint::new(position.row(), goal_column))
 3732                    } else {
 3733                        None
 3734                    }
 3735                } else {
 3736                    None
 3737                },
 3738            }),
 3739            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3740                selection_tail: selection_anchor,
 3741            }),
 3742        };
 3743
 3744        if !reset {
 3745            self.select_columns(position, goal_column, &display_map, window, cx);
 3746        }
 3747    }
 3748
 3749    fn update_selection(
 3750        &mut self,
 3751        position: DisplayPoint,
 3752        goal_column: u32,
 3753        scroll_delta: gpui::Point<f32>,
 3754        window: &mut Window,
 3755        cx: &mut Context<Self>,
 3756    ) {
 3757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3758
 3759        if self.columnar_selection_state.is_some() {
 3760            self.select_columns(position, goal_column, &display_map, window, cx);
 3761        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3762            let buffer = display_map.buffer_snapshot();
 3763            let head;
 3764            let tail;
 3765            let mode = self.selections.pending_mode().unwrap();
 3766            match &mode {
 3767                SelectMode::Character => {
 3768                    head = position.to_point(&display_map);
 3769                    tail = pending.tail().to_point(buffer);
 3770                }
 3771                SelectMode::Word(original_range) => {
 3772                    let offset = display_map
 3773                        .clip_point(position, Bias::Left)
 3774                        .to_offset(&display_map, Bias::Left);
 3775                    let original_range = original_range.to_offset(buffer);
 3776
 3777                    let head_offset = if buffer.is_inside_word(offset, None)
 3778                        || original_range.contains(&offset)
 3779                    {
 3780                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3781                        if word_range.start < original_range.start {
 3782                            word_range.start
 3783                        } else {
 3784                            word_range.end
 3785                        }
 3786                    } else {
 3787                        offset
 3788                    };
 3789
 3790                    head = head_offset.to_point(buffer);
 3791                    if head_offset <= original_range.start {
 3792                        tail = original_range.end.to_point(buffer);
 3793                    } else {
 3794                        tail = original_range.start.to_point(buffer);
 3795                    }
 3796                }
 3797                SelectMode::Line(original_range) => {
 3798                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3799
 3800                    let position = display_map
 3801                        .clip_point(position, Bias::Left)
 3802                        .to_point(&display_map);
 3803                    let line_start = display_map.prev_line_boundary(position).0;
 3804                    let next_line_start = buffer.clip_point(
 3805                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3806                        Bias::Left,
 3807                    );
 3808
 3809                    if line_start < original_range.start {
 3810                        head = line_start
 3811                    } else {
 3812                        head = next_line_start
 3813                    }
 3814
 3815                    if head <= original_range.start {
 3816                        tail = original_range.end;
 3817                    } else {
 3818                        tail = original_range.start;
 3819                    }
 3820                }
 3821                SelectMode::All => {
 3822                    return;
 3823                }
 3824            };
 3825
 3826            if head < tail {
 3827                pending.start = buffer.anchor_before(head);
 3828                pending.end = buffer.anchor_before(tail);
 3829                pending.reversed = true;
 3830            } else {
 3831                pending.start = buffer.anchor_before(tail);
 3832                pending.end = buffer.anchor_before(head);
 3833                pending.reversed = false;
 3834            }
 3835
 3836            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3837                s.set_pending(pending.clone(), mode);
 3838            });
 3839        } else {
 3840            log::error!("update_selection dispatched with no pending selection");
 3841            return;
 3842        }
 3843
 3844        self.apply_scroll_delta(scroll_delta, window, cx);
 3845        cx.notify();
 3846    }
 3847
 3848    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3849        self.columnar_selection_state.take();
 3850        if let Some(pending_mode) = self.selections.pending_mode() {
 3851            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3852            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3853                s.select(selections);
 3854                s.clear_pending();
 3855                if s.is_extending() {
 3856                    s.set_is_extending(false);
 3857                } else {
 3858                    s.set_select_mode(pending_mode);
 3859                }
 3860            });
 3861        }
 3862    }
 3863
 3864    fn select_columns(
 3865        &mut self,
 3866        head: DisplayPoint,
 3867        goal_column: u32,
 3868        display_map: &DisplaySnapshot,
 3869        window: &mut Window,
 3870        cx: &mut Context<Self>,
 3871    ) {
 3872        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3873            return;
 3874        };
 3875
 3876        let tail = match columnar_state {
 3877            ColumnarSelectionState::FromMouse {
 3878                selection_tail,
 3879                display_point,
 3880            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3881            ColumnarSelectionState::FromSelection { selection_tail } => {
 3882                selection_tail.to_display_point(display_map)
 3883            }
 3884        };
 3885
 3886        let start_row = cmp::min(tail.row(), head.row());
 3887        let end_row = cmp::max(tail.row(), head.row());
 3888        let start_column = cmp::min(tail.column(), goal_column);
 3889        let end_column = cmp::max(tail.column(), goal_column);
 3890        let reversed = start_column < tail.column();
 3891
 3892        let selection_ranges = (start_row.0..=end_row.0)
 3893            .map(DisplayRow)
 3894            .filter_map(|row| {
 3895                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3896                    || start_column <= display_map.line_len(row))
 3897                    && !display_map.is_block_line(row)
 3898                {
 3899                    let start = display_map
 3900                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3901                        .to_point(display_map);
 3902                    let end = display_map
 3903                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3904                        .to_point(display_map);
 3905                    if reversed {
 3906                        Some(end..start)
 3907                    } else {
 3908                        Some(start..end)
 3909                    }
 3910                } else {
 3911                    None
 3912                }
 3913            })
 3914            .collect::<Vec<_>>();
 3915        if selection_ranges.is_empty() {
 3916            return;
 3917        }
 3918
 3919        let ranges = match columnar_state {
 3920            ColumnarSelectionState::FromMouse { .. } => {
 3921                let mut non_empty_ranges = selection_ranges
 3922                    .iter()
 3923                    .filter(|selection_range| selection_range.start != selection_range.end)
 3924                    .peekable();
 3925                if non_empty_ranges.peek().is_some() {
 3926                    non_empty_ranges.cloned().collect()
 3927                } else {
 3928                    selection_ranges
 3929                }
 3930            }
 3931            _ => selection_ranges,
 3932        };
 3933
 3934        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3935            s.select_ranges(ranges);
 3936        });
 3937        cx.notify();
 3938    }
 3939
 3940    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3941        self.selections
 3942            .all_adjusted(snapshot)
 3943            .iter()
 3944            .any(|selection| !selection.is_empty())
 3945    }
 3946
 3947    pub fn has_pending_nonempty_selection(&self) -> bool {
 3948        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3949            Some(Selection { start, end, .. }) => start != end,
 3950            None => false,
 3951        };
 3952
 3953        pending_nonempty_selection
 3954            || (self.columnar_selection_state.is_some()
 3955                && self.selections.disjoint_anchors().len() > 1)
 3956    }
 3957
 3958    pub fn has_pending_selection(&self) -> bool {
 3959        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3960    }
 3961
 3962    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3963        self.selection_mark_mode = false;
 3964        self.selection_drag_state = SelectionDragState::None;
 3965
 3966        if self.clear_expanded_diff_hunks(cx) {
 3967            cx.notify();
 3968            return;
 3969        }
 3970        if self.dismiss_menus_and_popups(true, window, cx) {
 3971            return;
 3972        }
 3973
 3974        if self.mode.is_full()
 3975            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3976        {
 3977            return;
 3978        }
 3979
 3980        cx.propagate();
 3981    }
 3982
 3983    pub fn dismiss_menus_and_popups(
 3984        &mut self,
 3985        is_user_requested: bool,
 3986        window: &mut Window,
 3987        cx: &mut Context<Self>,
 3988    ) -> bool {
 3989        if self.take_rename(false, window, cx).is_some() {
 3990            return true;
 3991        }
 3992
 3993        if hide_hover(self, cx) {
 3994            return true;
 3995        }
 3996
 3997        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3998            return true;
 3999        }
 4000
 4001        if self.hide_context_menu(window, cx).is_some() {
 4002            return true;
 4003        }
 4004
 4005        if self.mouse_context_menu.take().is_some() {
 4006            return true;
 4007        }
 4008
 4009        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4010            return true;
 4011        }
 4012
 4013        if self.snippet_stack.pop().is_some() {
 4014            return true;
 4015        }
 4016
 4017        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4018            self.dismiss_diagnostics(cx);
 4019            return true;
 4020        }
 4021
 4022        false
 4023    }
 4024
 4025    fn linked_editing_ranges_for(
 4026        &self,
 4027        selection: Range<text::Anchor>,
 4028        cx: &App,
 4029    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4030        if self.linked_edit_ranges.is_empty() {
 4031            return None;
 4032        }
 4033        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4034            selection.end.buffer_id.and_then(|end_buffer_id| {
 4035                if selection.start.buffer_id != Some(end_buffer_id) {
 4036                    return None;
 4037                }
 4038                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4039                let snapshot = buffer.read(cx).snapshot();
 4040                self.linked_edit_ranges
 4041                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4042                    .map(|ranges| (ranges, snapshot, buffer))
 4043            })?;
 4044        use text::ToOffset as TO;
 4045        // find offset from the start of current range to current cursor position
 4046        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4047
 4048        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4049        let start_difference = start_offset - start_byte_offset;
 4050        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4051        let end_difference = end_offset - start_byte_offset;
 4052        // Current range has associated linked ranges.
 4053        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4054        for range in linked_ranges.iter() {
 4055            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4056            let end_offset = start_offset + end_difference;
 4057            let start_offset = start_offset + start_difference;
 4058            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4059                continue;
 4060            }
 4061            if self.selections.disjoint_anchor_ranges().any(|s| {
 4062                if s.start.buffer_id != selection.start.buffer_id
 4063                    || s.end.buffer_id != selection.end.buffer_id
 4064                {
 4065                    return false;
 4066                }
 4067                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4068                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4069            }) {
 4070                continue;
 4071            }
 4072            let start = buffer_snapshot.anchor_after(start_offset);
 4073            let end = buffer_snapshot.anchor_after(end_offset);
 4074            linked_edits
 4075                .entry(buffer.clone())
 4076                .or_default()
 4077                .push(start..end);
 4078        }
 4079        Some(linked_edits)
 4080    }
 4081
 4082    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4083        let text: Arc<str> = text.into();
 4084
 4085        if self.read_only(cx) {
 4086            return;
 4087        }
 4088
 4089        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4090
 4091        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4092        let mut bracket_inserted = false;
 4093        let mut edits = Vec::new();
 4094        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4095        let mut new_selections = Vec::with_capacity(selections.len());
 4096        let mut new_autoclose_regions = Vec::new();
 4097        let snapshot = self.buffer.read(cx).read(cx);
 4098        let mut clear_linked_edit_ranges = false;
 4099
 4100        for (selection, autoclose_region) in
 4101            self.selections_with_autoclose_regions(selections, &snapshot)
 4102        {
 4103            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4104                // Determine if the inserted text matches the opening or closing
 4105                // bracket of any of this language's bracket pairs.
 4106                let mut bracket_pair = None;
 4107                let mut is_bracket_pair_start = false;
 4108                let mut is_bracket_pair_end = false;
 4109                if !text.is_empty() {
 4110                    let mut bracket_pair_matching_end = None;
 4111                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4112                    //  and they are removing the character that triggered IME popup.
 4113                    for (pair, enabled) in scope.brackets() {
 4114                        if !pair.close && !pair.surround {
 4115                            continue;
 4116                        }
 4117
 4118                        if enabled && pair.start.ends_with(text.as_ref()) {
 4119                            let prefix_len = pair.start.len() - text.len();
 4120                            let preceding_text_matches_prefix = prefix_len == 0
 4121                                || (selection.start.column >= (prefix_len as u32)
 4122                                    && snapshot.contains_str_at(
 4123                                        Point::new(
 4124                                            selection.start.row,
 4125                                            selection.start.column - (prefix_len as u32),
 4126                                        ),
 4127                                        &pair.start[..prefix_len],
 4128                                    ));
 4129                            if preceding_text_matches_prefix {
 4130                                bracket_pair = Some(pair.clone());
 4131                                is_bracket_pair_start = true;
 4132                                break;
 4133                            }
 4134                        }
 4135                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4136                        {
 4137                            // take first bracket pair matching end, but don't break in case a later bracket
 4138                            // pair matches start
 4139                            bracket_pair_matching_end = Some(pair.clone());
 4140                        }
 4141                    }
 4142                    if let Some(end) = bracket_pair_matching_end
 4143                        && bracket_pair.is_none()
 4144                    {
 4145                        bracket_pair = Some(end);
 4146                        is_bracket_pair_end = true;
 4147                    }
 4148                }
 4149
 4150                if let Some(bracket_pair) = bracket_pair {
 4151                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4152                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4153                    let auto_surround =
 4154                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4155                    if selection.is_empty() {
 4156                        if is_bracket_pair_start {
 4157                            // If the inserted text is a suffix of an opening bracket and the
 4158                            // selection is preceded by the rest of the opening bracket, then
 4159                            // insert the closing bracket.
 4160                            let following_text_allows_autoclose = snapshot
 4161                                .chars_at(selection.start)
 4162                                .next()
 4163                                .is_none_or(|c| scope.should_autoclose_before(c));
 4164
 4165                            let preceding_text_allows_autoclose = selection.start.column == 0
 4166                                || snapshot
 4167                                    .reversed_chars_at(selection.start)
 4168                                    .next()
 4169                                    .is_none_or(|c| {
 4170                                        bracket_pair.start != bracket_pair.end
 4171                                            || !snapshot
 4172                                                .char_classifier_at(selection.start)
 4173                                                .is_word(c)
 4174                                    });
 4175
 4176                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4177                                && bracket_pair.start.len() == 1
 4178                            {
 4179                                let target = bracket_pair.start.chars().next().unwrap();
 4180                                let current_line_count = snapshot
 4181                                    .reversed_chars_at(selection.start)
 4182                                    .take_while(|&c| c != '\n')
 4183                                    .filter(|&c| c == target)
 4184                                    .count();
 4185                                current_line_count % 2 == 1
 4186                            } else {
 4187                                false
 4188                            };
 4189
 4190                            if autoclose
 4191                                && bracket_pair.close
 4192                                && following_text_allows_autoclose
 4193                                && preceding_text_allows_autoclose
 4194                                && !is_closing_quote
 4195                            {
 4196                                let anchor = snapshot.anchor_before(selection.end);
 4197                                new_selections.push((selection.map(|_| anchor), text.len()));
 4198                                new_autoclose_regions.push((
 4199                                    anchor,
 4200                                    text.len(),
 4201                                    selection.id,
 4202                                    bracket_pair.clone(),
 4203                                ));
 4204                                edits.push((
 4205                                    selection.range(),
 4206                                    format!("{}{}", text, bracket_pair.end).into(),
 4207                                ));
 4208                                bracket_inserted = true;
 4209                                continue;
 4210                            }
 4211                        }
 4212
 4213                        if let Some(region) = autoclose_region {
 4214                            // If the selection is followed by an auto-inserted closing bracket,
 4215                            // then don't insert that closing bracket again; just move the selection
 4216                            // past the closing bracket.
 4217                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4218                                && text.as_ref() == region.pair.end.as_str()
 4219                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4220                            if should_skip {
 4221                                let anchor = snapshot.anchor_after(selection.end);
 4222                                new_selections
 4223                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4224                                continue;
 4225                            }
 4226                        }
 4227
 4228                        let always_treat_brackets_as_autoclosed = snapshot
 4229                            .language_settings_at(selection.start, cx)
 4230                            .always_treat_brackets_as_autoclosed;
 4231                        if always_treat_brackets_as_autoclosed
 4232                            && is_bracket_pair_end
 4233                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4234                        {
 4235                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4236                            // and the inserted text is a closing bracket and the selection is followed
 4237                            // by the closing bracket then move the selection past the closing bracket.
 4238                            let anchor = snapshot.anchor_after(selection.end);
 4239                            new_selections.push((selection.map(|_| anchor), text.len()));
 4240                            continue;
 4241                        }
 4242                    }
 4243                    // If an opening bracket is 1 character long and is typed while
 4244                    // text is selected, then surround that text with the bracket pair.
 4245                    else if auto_surround
 4246                        && bracket_pair.surround
 4247                        && is_bracket_pair_start
 4248                        && bracket_pair.start.chars().count() == 1
 4249                    {
 4250                        edits.push((selection.start..selection.start, text.clone()));
 4251                        edits.push((
 4252                            selection.end..selection.end,
 4253                            bracket_pair.end.as_str().into(),
 4254                        ));
 4255                        bracket_inserted = true;
 4256                        new_selections.push((
 4257                            Selection {
 4258                                id: selection.id,
 4259                                start: snapshot.anchor_after(selection.start),
 4260                                end: snapshot.anchor_before(selection.end),
 4261                                reversed: selection.reversed,
 4262                                goal: selection.goal,
 4263                            },
 4264                            0,
 4265                        ));
 4266                        continue;
 4267                    }
 4268                }
 4269            }
 4270
 4271            if self.auto_replace_emoji_shortcode
 4272                && selection.is_empty()
 4273                && text.as_ref().ends_with(':')
 4274                && let Some(possible_emoji_short_code) =
 4275                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4276                && !possible_emoji_short_code.is_empty()
 4277                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4278            {
 4279                let emoji_shortcode_start = Point::new(
 4280                    selection.start.row,
 4281                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4282                );
 4283
 4284                // Remove shortcode from buffer
 4285                edits.push((
 4286                    emoji_shortcode_start..selection.start,
 4287                    "".to_string().into(),
 4288                ));
 4289                new_selections.push((
 4290                    Selection {
 4291                        id: selection.id,
 4292                        start: snapshot.anchor_after(emoji_shortcode_start),
 4293                        end: snapshot.anchor_before(selection.start),
 4294                        reversed: selection.reversed,
 4295                        goal: selection.goal,
 4296                    },
 4297                    0,
 4298                ));
 4299
 4300                // Insert emoji
 4301                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4302                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4303                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4304
 4305                continue;
 4306            }
 4307
 4308            // If not handling any auto-close operation, then just replace the selected
 4309            // text with the given input and move the selection to the end of the
 4310            // newly inserted text.
 4311            let anchor = snapshot.anchor_after(selection.end);
 4312            if !self.linked_edit_ranges.is_empty() {
 4313                let start_anchor = snapshot.anchor_before(selection.start);
 4314
 4315                let is_word_char = text.chars().next().is_none_or(|char| {
 4316                    let classifier = snapshot
 4317                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4318                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4319                    classifier.is_word(char)
 4320                });
 4321
 4322                if is_word_char {
 4323                    if let Some(ranges) = self
 4324                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4325                    {
 4326                        for (buffer, edits) in ranges {
 4327                            linked_edits
 4328                                .entry(buffer.clone())
 4329                                .or_default()
 4330                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4331                        }
 4332                    }
 4333                } else {
 4334                    clear_linked_edit_ranges = true;
 4335                }
 4336            }
 4337
 4338            new_selections.push((selection.map(|_| anchor), 0));
 4339            edits.push((selection.start..selection.end, text.clone()));
 4340        }
 4341
 4342        drop(snapshot);
 4343
 4344        self.transact(window, cx, |this, window, cx| {
 4345            if clear_linked_edit_ranges {
 4346                this.linked_edit_ranges.clear();
 4347            }
 4348            let initial_buffer_versions =
 4349                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4350
 4351            this.buffer.update(cx, |buffer, cx| {
 4352                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4353            });
 4354            for (buffer, edits) in linked_edits {
 4355                buffer.update(cx, |buffer, cx| {
 4356                    let snapshot = buffer.snapshot();
 4357                    let edits = edits
 4358                        .into_iter()
 4359                        .map(|(range, text)| {
 4360                            use text::ToPoint as TP;
 4361                            let end_point = TP::to_point(&range.end, &snapshot);
 4362                            let start_point = TP::to_point(&range.start, &snapshot);
 4363                            (start_point..end_point, text)
 4364                        })
 4365                        .sorted_by_key(|(range, _)| range.start);
 4366                    buffer.edit(edits, None, cx);
 4367                })
 4368            }
 4369            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4370            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4371            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4372            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4373                .zip(new_selection_deltas)
 4374                .map(|(selection, delta)| Selection {
 4375                    id: selection.id,
 4376                    start: selection.start + delta,
 4377                    end: selection.end + delta,
 4378                    reversed: selection.reversed,
 4379                    goal: SelectionGoal::None,
 4380                })
 4381                .collect::<Vec<_>>();
 4382
 4383            let mut i = 0;
 4384            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4385                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4386                let start = map.buffer_snapshot().anchor_before(position);
 4387                let end = map.buffer_snapshot().anchor_after(position);
 4388                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4389                    match existing_state
 4390                        .range
 4391                        .start
 4392                        .cmp(&start, map.buffer_snapshot())
 4393                    {
 4394                        Ordering::Less => i += 1,
 4395                        Ordering::Greater => break,
 4396                        Ordering::Equal => {
 4397                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4398                                Ordering::Less => i += 1,
 4399                                Ordering::Equal => break,
 4400                                Ordering::Greater => break,
 4401                            }
 4402                        }
 4403                    }
 4404                }
 4405                this.autoclose_regions.insert(
 4406                    i,
 4407                    AutocloseRegion {
 4408                        selection_id,
 4409                        range: start..end,
 4410                        pair,
 4411                    },
 4412                );
 4413            }
 4414
 4415            let had_active_edit_prediction = this.has_active_edit_prediction();
 4416            this.change_selections(
 4417                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4418                window,
 4419                cx,
 4420                |s| s.select(new_selections),
 4421            );
 4422
 4423            if !bracket_inserted
 4424                && let Some(on_type_format_task) =
 4425                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4426            {
 4427                on_type_format_task.detach_and_log_err(cx);
 4428            }
 4429
 4430            let editor_settings = EditorSettings::get_global(cx);
 4431            if bracket_inserted
 4432                && (editor_settings.auto_signature_help
 4433                    || editor_settings.show_signature_help_after_edits)
 4434            {
 4435                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4436            }
 4437
 4438            let trigger_in_words =
 4439                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4440            if this.hard_wrap.is_some() {
 4441                let latest: Range<Point> = this.selections.newest(&map).range();
 4442                if latest.is_empty()
 4443                    && this
 4444                        .buffer()
 4445                        .read(cx)
 4446                        .snapshot(cx)
 4447                        .line_len(MultiBufferRow(latest.start.row))
 4448                        == latest.start.column
 4449                {
 4450                    this.rewrap_impl(
 4451                        RewrapOptions {
 4452                            override_language_settings: true,
 4453                            preserve_existing_whitespace: true,
 4454                        },
 4455                        cx,
 4456                    )
 4457                }
 4458            }
 4459            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4460            refresh_linked_ranges(this, window, cx);
 4461            this.refresh_edit_prediction(true, false, window, cx);
 4462            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4463        });
 4464    }
 4465
 4466    fn find_possible_emoji_shortcode_at_position(
 4467        snapshot: &MultiBufferSnapshot,
 4468        position: Point,
 4469    ) -> Option<String> {
 4470        let mut chars = Vec::new();
 4471        let mut found_colon = false;
 4472        for char in snapshot.reversed_chars_at(position).take(100) {
 4473            // Found a possible emoji shortcode in the middle of the buffer
 4474            if found_colon {
 4475                if char.is_whitespace() {
 4476                    chars.reverse();
 4477                    return Some(chars.iter().collect());
 4478                }
 4479                // If the previous character is not a whitespace, we are in the middle of a word
 4480                // and we only want to complete the shortcode if the word is made up of other emojis
 4481                let mut containing_word = String::new();
 4482                for ch in snapshot
 4483                    .reversed_chars_at(position)
 4484                    .skip(chars.len() + 1)
 4485                    .take(100)
 4486                {
 4487                    if ch.is_whitespace() {
 4488                        break;
 4489                    }
 4490                    containing_word.push(ch);
 4491                }
 4492                let containing_word = containing_word.chars().rev().collect::<String>();
 4493                if util::word_consists_of_emojis(containing_word.as_str()) {
 4494                    chars.reverse();
 4495                    return Some(chars.iter().collect());
 4496                }
 4497            }
 4498
 4499            if char.is_whitespace() || !char.is_ascii() {
 4500                return None;
 4501            }
 4502            if char == ':' {
 4503                found_colon = true;
 4504            } else {
 4505                chars.push(char);
 4506            }
 4507        }
 4508        // Found a possible emoji shortcode at the beginning of the buffer
 4509        chars.reverse();
 4510        Some(chars.iter().collect())
 4511    }
 4512
 4513    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4514        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4515        self.transact(window, cx, |this, window, cx| {
 4516            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4517                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4518                let multi_buffer = this.buffer.read(cx);
 4519                let buffer = multi_buffer.snapshot(cx);
 4520                selections
 4521                    .iter()
 4522                    .map(|selection| {
 4523                        let start_point = selection.start.to_point(&buffer);
 4524                        let mut existing_indent =
 4525                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4526                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4527                        let start = selection.start;
 4528                        let end = selection.end;
 4529                        let selection_is_empty = start == end;
 4530                        let language_scope = buffer.language_scope_at(start);
 4531                        let (
 4532                            comment_delimiter,
 4533                            doc_delimiter,
 4534                            insert_extra_newline,
 4535                            indent_on_newline,
 4536                            indent_on_extra_newline,
 4537                        ) = if let Some(language) = &language_scope {
 4538                            let mut insert_extra_newline =
 4539                                insert_extra_newline_brackets(&buffer, start..end, language)
 4540                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4541
 4542                            // Comment extension on newline is allowed only for cursor selections
 4543                            let comment_delimiter = maybe!({
 4544                                if !selection_is_empty {
 4545                                    return None;
 4546                                }
 4547
 4548                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4549                                    return None;
 4550                                }
 4551
 4552                                let delimiters = language.line_comment_prefixes();
 4553                                let max_len_of_delimiter =
 4554                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4555                                let (snapshot, range) =
 4556                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4557
 4558                                let num_of_whitespaces = snapshot
 4559                                    .chars_for_range(range.clone())
 4560                                    .take_while(|c| c.is_whitespace())
 4561                                    .count();
 4562                                let comment_candidate = snapshot
 4563                                    .chars_for_range(range.clone())
 4564                                    .skip(num_of_whitespaces)
 4565                                    .take(max_len_of_delimiter)
 4566                                    .collect::<String>();
 4567                                let (delimiter, trimmed_len) = delimiters
 4568                                    .iter()
 4569                                    .filter_map(|delimiter| {
 4570                                        let prefix = delimiter.trim_end();
 4571                                        if comment_candidate.starts_with(prefix) {
 4572                                            Some((delimiter, prefix.len()))
 4573                                        } else {
 4574                                            None
 4575                                        }
 4576                                    })
 4577                                    .max_by_key(|(_, len)| *len)?;
 4578
 4579                                if let Some(BlockCommentConfig {
 4580                                    start: block_start, ..
 4581                                }) = language.block_comment()
 4582                                {
 4583                                    let block_start_trimmed = block_start.trim_end();
 4584                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4585                                        let line_content = snapshot
 4586                                            .chars_for_range(range)
 4587                                            .skip(num_of_whitespaces)
 4588                                            .take(block_start_trimmed.len())
 4589                                            .collect::<String>();
 4590
 4591                                        if line_content.starts_with(block_start_trimmed) {
 4592                                            return None;
 4593                                        }
 4594                                    }
 4595                                }
 4596
 4597                                let cursor_is_placed_after_comment_marker =
 4598                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4599                                if cursor_is_placed_after_comment_marker {
 4600                                    Some(delimiter.clone())
 4601                                } else {
 4602                                    None
 4603                                }
 4604                            });
 4605
 4606                            let mut indent_on_newline = IndentSize::spaces(0);
 4607                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4608
 4609                            let doc_delimiter = maybe!({
 4610                                if !selection_is_empty {
 4611                                    return None;
 4612                                }
 4613
 4614                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4615                                    return None;
 4616                                }
 4617
 4618                                let BlockCommentConfig {
 4619                                    start: start_tag,
 4620                                    end: end_tag,
 4621                                    prefix: delimiter,
 4622                                    tab_size: len,
 4623                                } = language.documentation_comment()?;
 4624                                let is_within_block_comment = buffer
 4625                                    .language_scope_at(start_point)
 4626                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4627                                if !is_within_block_comment {
 4628                                    return None;
 4629                                }
 4630
 4631                                let (snapshot, range) =
 4632                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4633
 4634                                let num_of_whitespaces = snapshot
 4635                                    .chars_for_range(range.clone())
 4636                                    .take_while(|c| c.is_whitespace())
 4637                                    .count();
 4638
 4639                                // 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.
 4640                                let column = start_point.column;
 4641                                let cursor_is_after_start_tag = {
 4642                                    let start_tag_len = start_tag.len();
 4643                                    let start_tag_line = snapshot
 4644                                        .chars_for_range(range.clone())
 4645                                        .skip(num_of_whitespaces)
 4646                                        .take(start_tag_len)
 4647                                        .collect::<String>();
 4648                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4649                                        num_of_whitespaces + start_tag_len <= column as usize
 4650                                    } else {
 4651                                        false
 4652                                    }
 4653                                };
 4654
 4655                                let cursor_is_after_delimiter = {
 4656                                    let delimiter_trim = delimiter.trim_end();
 4657                                    let delimiter_line = snapshot
 4658                                        .chars_for_range(range.clone())
 4659                                        .skip(num_of_whitespaces)
 4660                                        .take(delimiter_trim.len())
 4661                                        .collect::<String>();
 4662                                    if delimiter_line.starts_with(delimiter_trim) {
 4663                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4664                                    } else {
 4665                                        false
 4666                                    }
 4667                                };
 4668
 4669                                let cursor_is_before_end_tag_if_exists = {
 4670                                    let mut char_position = 0u32;
 4671                                    let mut end_tag_offset = None;
 4672
 4673                                    'outer: for chunk in snapshot.text_for_range(range) {
 4674                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4675                                            let chars_before_match =
 4676                                                chunk[..byte_pos].chars().count() as u32;
 4677                                            end_tag_offset =
 4678                                                Some(char_position + chars_before_match);
 4679                                            break 'outer;
 4680                                        }
 4681                                        char_position += chunk.chars().count() as u32;
 4682                                    }
 4683
 4684                                    if let Some(end_tag_offset) = end_tag_offset {
 4685                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4686                                        if cursor_is_after_start_tag {
 4687                                            if cursor_is_before_end_tag {
 4688                                                insert_extra_newline = true;
 4689                                            }
 4690                                            let cursor_is_at_start_of_end_tag =
 4691                                                column == end_tag_offset;
 4692                                            if cursor_is_at_start_of_end_tag {
 4693                                                indent_on_extra_newline.len = *len;
 4694                                            }
 4695                                        }
 4696                                        cursor_is_before_end_tag
 4697                                    } else {
 4698                                        true
 4699                                    }
 4700                                };
 4701
 4702                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4703                                    && cursor_is_before_end_tag_if_exists
 4704                                {
 4705                                    if cursor_is_after_start_tag {
 4706                                        indent_on_newline.len = *len;
 4707                                    }
 4708                                    Some(delimiter.clone())
 4709                                } else {
 4710                                    None
 4711                                }
 4712                            });
 4713
 4714                            (
 4715                                comment_delimiter,
 4716                                doc_delimiter,
 4717                                insert_extra_newline,
 4718                                indent_on_newline,
 4719                                indent_on_extra_newline,
 4720                            )
 4721                        } else {
 4722                            (
 4723                                None,
 4724                                None,
 4725                                false,
 4726                                IndentSize::default(),
 4727                                IndentSize::default(),
 4728                            )
 4729                        };
 4730
 4731                        let prevent_auto_indent = doc_delimiter.is_some();
 4732                        let delimiter = comment_delimiter.or(doc_delimiter);
 4733
 4734                        let capacity_for_delimiter =
 4735                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4736                        let mut new_text = String::with_capacity(
 4737                            1 + capacity_for_delimiter
 4738                                + existing_indent.len as usize
 4739                                + indent_on_newline.len as usize
 4740                                + indent_on_extra_newline.len as usize,
 4741                        );
 4742                        new_text.push('\n');
 4743                        new_text.extend(existing_indent.chars());
 4744                        new_text.extend(indent_on_newline.chars());
 4745
 4746                        if let Some(delimiter) = &delimiter {
 4747                            new_text.push_str(delimiter);
 4748                        }
 4749
 4750                        if insert_extra_newline {
 4751                            new_text.push('\n');
 4752                            new_text.extend(existing_indent.chars());
 4753                            new_text.extend(indent_on_extra_newline.chars());
 4754                        }
 4755
 4756                        let anchor = buffer.anchor_after(end);
 4757                        let new_selection = selection.map(|_| anchor);
 4758                        (
 4759                            ((start..end, new_text), prevent_auto_indent),
 4760                            (insert_extra_newline, new_selection),
 4761                        )
 4762                    })
 4763                    .unzip()
 4764            };
 4765
 4766            let mut auto_indent_edits = Vec::new();
 4767            let mut edits = Vec::new();
 4768            for (edit, prevent_auto_indent) in edits_with_flags {
 4769                if prevent_auto_indent {
 4770                    edits.push(edit);
 4771                } else {
 4772                    auto_indent_edits.push(edit);
 4773                }
 4774            }
 4775            if !edits.is_empty() {
 4776                this.edit(edits, cx);
 4777            }
 4778            if !auto_indent_edits.is_empty() {
 4779                this.edit_with_autoindent(auto_indent_edits, cx);
 4780            }
 4781
 4782            let buffer = this.buffer.read(cx).snapshot(cx);
 4783            let new_selections = selection_info
 4784                .into_iter()
 4785                .map(|(extra_newline_inserted, new_selection)| {
 4786                    let mut cursor = new_selection.end.to_point(&buffer);
 4787                    if extra_newline_inserted {
 4788                        cursor.row -= 1;
 4789                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4790                    }
 4791                    new_selection.map(|_| cursor)
 4792                })
 4793                .collect();
 4794
 4795            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4796            this.refresh_edit_prediction(true, false, window, cx);
 4797        });
 4798    }
 4799
 4800    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4802
 4803        let buffer = self.buffer.read(cx);
 4804        let snapshot = buffer.snapshot(cx);
 4805
 4806        let mut edits = Vec::new();
 4807        let mut rows = Vec::new();
 4808
 4809        for (rows_inserted, selection) in self
 4810            .selections
 4811            .all_adjusted(&self.display_snapshot(cx))
 4812            .into_iter()
 4813            .enumerate()
 4814        {
 4815            let cursor = selection.head();
 4816            let row = cursor.row;
 4817
 4818            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4819
 4820            let newline = "\n".to_string();
 4821            edits.push((start_of_line..start_of_line, newline));
 4822
 4823            rows.push(row + rows_inserted as u32);
 4824        }
 4825
 4826        self.transact(window, cx, |editor, window, cx| {
 4827            editor.edit(edits, cx);
 4828
 4829            editor.change_selections(Default::default(), window, cx, |s| {
 4830                let mut index = 0;
 4831                s.move_cursors_with(|map, _, _| {
 4832                    let row = rows[index];
 4833                    index += 1;
 4834
 4835                    let point = Point::new(row, 0);
 4836                    let boundary = map.next_line_boundary(point).1;
 4837                    let clipped = map.clip_point(boundary, Bias::Left);
 4838
 4839                    (clipped, SelectionGoal::None)
 4840                });
 4841            });
 4842
 4843            let mut indent_edits = Vec::new();
 4844            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4845            for row in rows {
 4846                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4847                for (row, indent) in indents {
 4848                    if indent.len == 0 {
 4849                        continue;
 4850                    }
 4851
 4852                    let text = match indent.kind {
 4853                        IndentKind::Space => " ".repeat(indent.len as usize),
 4854                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4855                    };
 4856                    let point = Point::new(row.0, 0);
 4857                    indent_edits.push((point..point, text));
 4858                }
 4859            }
 4860            editor.edit(indent_edits, cx);
 4861        });
 4862    }
 4863
 4864    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4865        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4866
 4867        let buffer = self.buffer.read(cx);
 4868        let snapshot = buffer.snapshot(cx);
 4869
 4870        let mut edits = Vec::new();
 4871        let mut rows = Vec::new();
 4872        let mut rows_inserted = 0;
 4873
 4874        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4875            let cursor = selection.head();
 4876            let row = cursor.row;
 4877
 4878            let point = Point::new(row + 1, 0);
 4879            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4880
 4881            let newline = "\n".to_string();
 4882            edits.push((start_of_line..start_of_line, newline));
 4883
 4884            rows_inserted += 1;
 4885            rows.push(row + rows_inserted);
 4886        }
 4887
 4888        self.transact(window, cx, |editor, window, cx| {
 4889            editor.edit(edits, cx);
 4890
 4891            editor.change_selections(Default::default(), window, cx, |s| {
 4892                let mut index = 0;
 4893                s.move_cursors_with(|map, _, _| {
 4894                    let row = rows[index];
 4895                    index += 1;
 4896
 4897                    let point = Point::new(row, 0);
 4898                    let boundary = map.next_line_boundary(point).1;
 4899                    let clipped = map.clip_point(boundary, Bias::Left);
 4900
 4901                    (clipped, SelectionGoal::None)
 4902                });
 4903            });
 4904
 4905            let mut indent_edits = Vec::new();
 4906            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4907            for row in rows {
 4908                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4909                for (row, indent) in indents {
 4910                    if indent.len == 0 {
 4911                        continue;
 4912                    }
 4913
 4914                    let text = match indent.kind {
 4915                        IndentKind::Space => " ".repeat(indent.len as usize),
 4916                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4917                    };
 4918                    let point = Point::new(row.0, 0);
 4919                    indent_edits.push((point..point, text));
 4920                }
 4921            }
 4922            editor.edit(indent_edits, cx);
 4923        });
 4924    }
 4925
 4926    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4927        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4928            original_indent_columns: Vec::new(),
 4929        });
 4930        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4931    }
 4932
 4933    fn insert_with_autoindent_mode(
 4934        &mut self,
 4935        text: &str,
 4936        autoindent_mode: Option<AutoindentMode>,
 4937        window: &mut Window,
 4938        cx: &mut Context<Self>,
 4939    ) {
 4940        if self.read_only(cx) {
 4941            return;
 4942        }
 4943
 4944        let text: Arc<str> = text.into();
 4945        self.transact(window, cx, |this, window, cx| {
 4946            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4947            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4948                let anchors = {
 4949                    let snapshot = buffer.read(cx);
 4950                    old_selections
 4951                        .iter()
 4952                        .map(|s| {
 4953                            let anchor = snapshot.anchor_after(s.head());
 4954                            s.map(|_| anchor)
 4955                        })
 4956                        .collect::<Vec<_>>()
 4957                };
 4958                buffer.edit(
 4959                    old_selections
 4960                        .iter()
 4961                        .map(|s| (s.start..s.end, text.clone())),
 4962                    autoindent_mode,
 4963                    cx,
 4964                );
 4965                anchors
 4966            });
 4967
 4968            this.change_selections(Default::default(), window, cx, |s| {
 4969                s.select_anchors(selection_anchors);
 4970            });
 4971
 4972            cx.notify();
 4973        });
 4974    }
 4975
 4976    fn trigger_completion_on_input(
 4977        &mut self,
 4978        text: &str,
 4979        trigger_in_words: bool,
 4980        window: &mut Window,
 4981        cx: &mut Context<Self>,
 4982    ) {
 4983        let completions_source = self
 4984            .context_menu
 4985            .borrow()
 4986            .as_ref()
 4987            .and_then(|menu| match menu {
 4988                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4989                CodeContextMenu::CodeActions(_) => None,
 4990            });
 4991
 4992        match completions_source {
 4993            Some(CompletionsMenuSource::Words { .. }) => {
 4994                self.open_or_update_completions_menu(
 4995                    Some(CompletionsMenuSource::Words {
 4996                        ignore_threshold: false,
 4997                    }),
 4998                    None,
 4999                    window,
 5000                    cx,
 5001                );
 5002            }
 5003            Some(CompletionsMenuSource::Normal)
 5004            | Some(CompletionsMenuSource::SnippetChoices)
 5005            | None
 5006                if self.is_completion_trigger(
 5007                    text,
 5008                    trigger_in_words,
 5009                    completions_source.is_some(),
 5010                    cx,
 5011                ) =>
 5012            {
 5013                self.show_completions(
 5014                    &ShowCompletions {
 5015                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5016                    },
 5017                    window,
 5018                    cx,
 5019                )
 5020            }
 5021            _ => {
 5022                self.hide_context_menu(window, cx);
 5023            }
 5024        }
 5025    }
 5026
 5027    fn is_completion_trigger(
 5028        &self,
 5029        text: &str,
 5030        trigger_in_words: bool,
 5031        menu_is_open: bool,
 5032        cx: &mut Context<Self>,
 5033    ) -> bool {
 5034        let position = self.selections.newest_anchor().head();
 5035        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5036            return false;
 5037        };
 5038
 5039        if let Some(completion_provider) = &self.completion_provider {
 5040            completion_provider.is_completion_trigger(
 5041                &buffer,
 5042                position.text_anchor,
 5043                text,
 5044                trigger_in_words,
 5045                menu_is_open,
 5046                cx,
 5047            )
 5048        } else {
 5049            false
 5050        }
 5051    }
 5052
 5053    /// If any empty selections is touching the start of its innermost containing autoclose
 5054    /// region, expand it to select the brackets.
 5055    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5056        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5057        let buffer = self.buffer.read(cx).read(cx);
 5058        let new_selections = self
 5059            .selections_with_autoclose_regions(selections, &buffer)
 5060            .map(|(mut selection, region)| {
 5061                if !selection.is_empty() {
 5062                    return selection;
 5063                }
 5064
 5065                if let Some(region) = region {
 5066                    let mut range = region.range.to_offset(&buffer);
 5067                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5068                        range.start -= region.pair.start.len();
 5069                        if buffer.contains_str_at(range.start, &region.pair.start)
 5070                            && buffer.contains_str_at(range.end, &region.pair.end)
 5071                        {
 5072                            range.end += region.pair.end.len();
 5073                            selection.start = range.start;
 5074                            selection.end = range.end;
 5075
 5076                            return selection;
 5077                        }
 5078                    }
 5079                }
 5080
 5081                let always_treat_brackets_as_autoclosed = buffer
 5082                    .language_settings_at(selection.start, cx)
 5083                    .always_treat_brackets_as_autoclosed;
 5084
 5085                if !always_treat_brackets_as_autoclosed {
 5086                    return selection;
 5087                }
 5088
 5089                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5090                    for (pair, enabled) in scope.brackets() {
 5091                        if !enabled || !pair.close {
 5092                            continue;
 5093                        }
 5094
 5095                        if buffer.contains_str_at(selection.start, &pair.end) {
 5096                            let pair_start_len = pair.start.len();
 5097                            if buffer.contains_str_at(
 5098                                selection.start.saturating_sub(pair_start_len),
 5099                                &pair.start,
 5100                            ) {
 5101                                selection.start -= pair_start_len;
 5102                                selection.end += pair.end.len();
 5103
 5104                                return selection;
 5105                            }
 5106                        }
 5107                    }
 5108                }
 5109
 5110                selection
 5111            })
 5112            .collect();
 5113
 5114        drop(buffer);
 5115        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5116            selections.select(new_selections)
 5117        });
 5118    }
 5119
 5120    /// Iterate the given selections, and for each one, find the smallest surrounding
 5121    /// autoclose region. This uses the ordering of the selections and the autoclose
 5122    /// regions to avoid repeated comparisons.
 5123    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5124        &'a self,
 5125        selections: impl IntoIterator<Item = Selection<D>>,
 5126        buffer: &'a MultiBufferSnapshot,
 5127    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5128        let mut i = 0;
 5129        let mut regions = self.autoclose_regions.as_slice();
 5130        selections.into_iter().map(move |selection| {
 5131            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5132
 5133            let mut enclosing = None;
 5134            while let Some(pair_state) = regions.get(i) {
 5135                if pair_state.range.end.to_offset(buffer) < range.start {
 5136                    regions = &regions[i + 1..];
 5137                    i = 0;
 5138                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5139                    break;
 5140                } else {
 5141                    if pair_state.selection_id == selection.id {
 5142                        enclosing = Some(pair_state);
 5143                    }
 5144                    i += 1;
 5145                }
 5146            }
 5147
 5148            (selection, enclosing)
 5149        })
 5150    }
 5151
 5152    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5153    fn invalidate_autoclose_regions(
 5154        &mut self,
 5155        mut selections: &[Selection<Anchor>],
 5156        buffer: &MultiBufferSnapshot,
 5157    ) {
 5158        self.autoclose_regions.retain(|state| {
 5159            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5160                return false;
 5161            }
 5162
 5163            let mut i = 0;
 5164            while let Some(selection) = selections.get(i) {
 5165                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5166                    selections = &selections[1..];
 5167                    continue;
 5168                }
 5169                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5170                    break;
 5171                }
 5172                if selection.id == state.selection_id {
 5173                    return true;
 5174                } else {
 5175                    i += 1;
 5176                }
 5177            }
 5178            false
 5179        });
 5180    }
 5181
 5182    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5183        let offset = position.to_offset(buffer);
 5184        let (word_range, kind) =
 5185            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5186        if offset > word_range.start && kind == Some(CharKind::Word) {
 5187            Some(
 5188                buffer
 5189                    .text_for_range(word_range.start..offset)
 5190                    .collect::<String>(),
 5191            )
 5192        } else {
 5193            None
 5194        }
 5195    }
 5196
 5197    pub fn toggle_inline_values(
 5198        &mut self,
 5199        _: &ToggleInlineValues,
 5200        _: &mut Window,
 5201        cx: &mut Context<Self>,
 5202    ) {
 5203        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5204
 5205        self.refresh_inline_values(cx);
 5206    }
 5207
 5208    pub fn toggle_inlay_hints(
 5209        &mut self,
 5210        _: &ToggleInlayHints,
 5211        _: &mut Window,
 5212        cx: &mut Context<Self>,
 5213    ) {
 5214        self.refresh_inlay_hints(
 5215            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5216            cx,
 5217        );
 5218    }
 5219
 5220    pub fn inlay_hints_enabled(&self) -> bool {
 5221        self.inlay_hint_cache.enabled
 5222    }
 5223
 5224    pub fn inline_values_enabled(&self) -> bool {
 5225        self.inline_value_cache.enabled
 5226    }
 5227
 5228    #[cfg(any(test, feature = "test-support"))]
 5229    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5230        self.display_map
 5231            .read(cx)
 5232            .current_inlays()
 5233            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5234            .cloned()
 5235            .collect()
 5236    }
 5237
 5238    #[cfg(any(test, feature = "test-support"))]
 5239    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5240        self.display_map
 5241            .read(cx)
 5242            .current_inlays()
 5243            .cloned()
 5244            .collect()
 5245    }
 5246
 5247    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5248        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5249            return;
 5250        }
 5251
 5252        let reason_description = reason.description();
 5253        let ignore_debounce = matches!(
 5254            reason,
 5255            InlayHintRefreshReason::SettingsChange(_)
 5256                | InlayHintRefreshReason::Toggle(_)
 5257                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5258                | InlayHintRefreshReason::ModifiersChanged(_)
 5259        );
 5260        let (invalidate_cache, required_languages) = match reason {
 5261            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5262                match self.inlay_hint_cache.modifiers_override(enabled) {
 5263                    Some(enabled) => {
 5264                        if enabled {
 5265                            (InvalidationStrategy::RefreshRequested, None)
 5266                        } else {
 5267                            self.clear_inlay_hints(cx);
 5268                            return;
 5269                        }
 5270                    }
 5271                    None => return,
 5272                }
 5273            }
 5274            InlayHintRefreshReason::Toggle(enabled) => {
 5275                if self.inlay_hint_cache.toggle(enabled) {
 5276                    if enabled {
 5277                        (InvalidationStrategy::RefreshRequested, None)
 5278                    } else {
 5279                        self.clear_inlay_hints(cx);
 5280                        return;
 5281                    }
 5282                } else {
 5283                    return;
 5284                }
 5285            }
 5286            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5287                match self.inlay_hint_cache.update_settings(
 5288                    &self.buffer,
 5289                    new_settings,
 5290                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5291                    cx,
 5292                ) {
 5293                    ControlFlow::Break(Some(InlaySplice {
 5294                        to_remove,
 5295                        to_insert,
 5296                    })) => {
 5297                        self.splice_inlays(&to_remove, to_insert, cx);
 5298                        return;
 5299                    }
 5300                    ControlFlow::Break(None) => return,
 5301                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5302                }
 5303            }
 5304            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5305                if let Some(InlaySplice {
 5306                    to_remove,
 5307                    to_insert,
 5308                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5309                {
 5310                    self.splice_inlays(&to_remove, to_insert, cx);
 5311                }
 5312                self.display_map.update(cx, |display_map, cx| {
 5313                    display_map.remove_inlays_for_excerpts(&excerpts_removed, cx)
 5314                });
 5315                return;
 5316            }
 5317            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5318            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5319                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5320            }
 5321            InlayHintRefreshReason::RefreshRequested => {
 5322                (InvalidationStrategy::RefreshRequested, None)
 5323            }
 5324        };
 5325
 5326        let mut visible_excerpts = self.visible_excerpts(required_languages.as_ref(), cx);
 5327        visible_excerpts.retain(|_, (buffer, _, _)| {
 5328            self.registered_buffers
 5329                .contains_key(&buffer.read(cx).remote_id())
 5330        });
 5331
 5332        if let Some(InlaySplice {
 5333            to_remove,
 5334            to_insert,
 5335        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5336            reason_description,
 5337            visible_excerpts,
 5338            invalidate_cache,
 5339            ignore_debounce,
 5340            cx,
 5341        ) {
 5342            self.splice_inlays(&to_remove, to_insert, cx);
 5343        }
 5344    }
 5345
 5346    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5347        self.splice_inlays(
 5348            &self
 5349                .visible_inlay_hints(cx)
 5350                .map(|inlay| inlay.id)
 5351                .collect::<Vec<_>>(),
 5352            Vec::new(),
 5353            cx,
 5354        );
 5355    }
 5356
 5357    fn visible_inlay_hints<'a>(
 5358        &'a self,
 5359        cx: &'a Context<Editor>,
 5360    ) -> impl Iterator<Item = &'a Inlay> {
 5361        self.display_map
 5362            .read(cx)
 5363            .current_inlays()
 5364            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5365    }
 5366
 5367    pub fn visible_excerpts(
 5368        &self,
 5369        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5370        cx: &mut Context<Editor>,
 5371    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5372        let Some(project) = self.project() else {
 5373            return HashMap::default();
 5374        };
 5375        let project = project.read(cx);
 5376        let multi_buffer = self.buffer().read(cx);
 5377        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5378        let multi_buffer_visible_start = self
 5379            .scroll_manager
 5380            .anchor()
 5381            .anchor
 5382            .to_point(&multi_buffer_snapshot);
 5383        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5384            multi_buffer_visible_start
 5385                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5386            Bias::Left,
 5387        );
 5388        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5389        multi_buffer_snapshot
 5390            .range_to_buffer_ranges(multi_buffer_visible_range)
 5391            .into_iter()
 5392            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5393            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5394                let buffer_file = project::File::from_dyn(buffer.file())?;
 5395                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5396                let worktree_entry = buffer_worktree
 5397                    .read(cx)
 5398                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5399                if worktree_entry.is_ignored {
 5400                    return None;
 5401                }
 5402
 5403                let language = buffer.language()?;
 5404                if let Some(restrict_to_languages) = restrict_to_languages
 5405                    && !restrict_to_languages.contains(language)
 5406                {
 5407                    return None;
 5408                }
 5409                Some((
 5410                    excerpt_id,
 5411                    (
 5412                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5413                        buffer.version().clone(),
 5414                        excerpt_visible_range,
 5415                    ),
 5416                ))
 5417            })
 5418            .collect()
 5419    }
 5420
 5421    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5422        TextLayoutDetails {
 5423            text_system: window.text_system().clone(),
 5424            editor_style: self.style.clone().unwrap(),
 5425            rem_size: window.rem_size(),
 5426            scroll_anchor: self.scroll_manager.anchor(),
 5427            visible_rows: self.visible_line_count(),
 5428            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5429        }
 5430    }
 5431
 5432    pub fn splice_inlays(
 5433        &self,
 5434        to_remove: &[InlayId],
 5435        to_insert: Vec<Inlay>,
 5436        cx: &mut Context<Self>,
 5437    ) {
 5438        self.display_map.update(cx, |display_map, cx| {
 5439            display_map.splice_inlays(to_remove, to_insert, cx)
 5440        });
 5441        cx.notify();
 5442    }
 5443
 5444    fn trigger_on_type_formatting(
 5445        &self,
 5446        input: String,
 5447        window: &mut Window,
 5448        cx: &mut Context<Self>,
 5449    ) -> Option<Task<Result<()>>> {
 5450        if input.len() != 1 {
 5451            return None;
 5452        }
 5453
 5454        let project = self.project()?;
 5455        let position = self.selections.newest_anchor().head();
 5456        let (buffer, buffer_position) = self
 5457            .buffer
 5458            .read(cx)
 5459            .text_anchor_for_position(position, cx)?;
 5460
 5461        let settings = language_settings::language_settings(
 5462            buffer
 5463                .read(cx)
 5464                .language_at(buffer_position)
 5465                .map(|l| l.name()),
 5466            buffer.read(cx).file(),
 5467            cx,
 5468        );
 5469        if !settings.use_on_type_format {
 5470            return None;
 5471        }
 5472
 5473        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5474        // hence we do LSP request & edit on host side only — add formats to host's history.
 5475        let push_to_lsp_host_history = true;
 5476        // If this is not the host, append its history with new edits.
 5477        let push_to_client_history = project.read(cx).is_via_collab();
 5478
 5479        let on_type_formatting = project.update(cx, |project, cx| {
 5480            project.on_type_format(
 5481                buffer.clone(),
 5482                buffer_position,
 5483                input,
 5484                push_to_lsp_host_history,
 5485                cx,
 5486            )
 5487        });
 5488        Some(cx.spawn_in(window, async move |editor, cx| {
 5489            if let Some(transaction) = on_type_formatting.await? {
 5490                if push_to_client_history {
 5491                    buffer
 5492                        .update(cx, |buffer, _| {
 5493                            buffer.push_transaction(transaction, Instant::now());
 5494                            buffer.finalize_last_transaction();
 5495                        })
 5496                        .ok();
 5497                }
 5498                editor.update(cx, |editor, cx| {
 5499                    editor.refresh_document_highlights(cx);
 5500                })?;
 5501            }
 5502            Ok(())
 5503        }))
 5504    }
 5505
 5506    pub fn show_word_completions(
 5507        &mut self,
 5508        _: &ShowWordCompletions,
 5509        window: &mut Window,
 5510        cx: &mut Context<Self>,
 5511    ) {
 5512        self.open_or_update_completions_menu(
 5513            Some(CompletionsMenuSource::Words {
 5514                ignore_threshold: true,
 5515            }),
 5516            None,
 5517            window,
 5518            cx,
 5519        );
 5520    }
 5521
 5522    pub fn show_completions(
 5523        &mut self,
 5524        options: &ShowCompletions,
 5525        window: &mut Window,
 5526        cx: &mut Context<Self>,
 5527    ) {
 5528        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5529    }
 5530
 5531    fn open_or_update_completions_menu(
 5532        &mut self,
 5533        requested_source: Option<CompletionsMenuSource>,
 5534        trigger: Option<&str>,
 5535        window: &mut Window,
 5536        cx: &mut Context<Self>,
 5537    ) {
 5538        if self.pending_rename.is_some() {
 5539            return;
 5540        }
 5541
 5542        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5543
 5544        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5545        // inserted and selected. To handle that case, the start of the selection is used so that
 5546        // the menu starts with all choices.
 5547        let position = self
 5548            .selections
 5549            .newest_anchor()
 5550            .start
 5551            .bias_right(&multibuffer_snapshot);
 5552        if position.diff_base_anchor.is_some() {
 5553            return;
 5554        }
 5555        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5556        let Some(buffer) = buffer_position
 5557            .buffer_id
 5558            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5559        else {
 5560            return;
 5561        };
 5562        let buffer_snapshot = buffer.read(cx).snapshot();
 5563
 5564        let query: Option<Arc<String>> =
 5565            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5566                .map(|query| query.into());
 5567
 5568        drop(multibuffer_snapshot);
 5569
 5570        // Hide the current completions menu when query is empty. Without this, cached
 5571        // completions from before the trigger char may be reused (#32774).
 5572        if query.is_none() {
 5573            let menu_is_open = matches!(
 5574                self.context_menu.borrow().as_ref(),
 5575                Some(CodeContextMenu::Completions(_))
 5576            );
 5577            if menu_is_open {
 5578                self.hide_context_menu(window, cx);
 5579            }
 5580        }
 5581
 5582        let mut ignore_word_threshold = false;
 5583        let provider = match requested_source {
 5584            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5585            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5586                ignore_word_threshold = ignore_threshold;
 5587                None
 5588            }
 5589            Some(CompletionsMenuSource::SnippetChoices) => {
 5590                log::error!("bug: SnippetChoices requested_source is not handled");
 5591                None
 5592            }
 5593        };
 5594
 5595        let sort_completions = provider
 5596            .as_ref()
 5597            .is_some_and(|provider| provider.sort_completions());
 5598
 5599        let filter_completions = provider
 5600            .as_ref()
 5601            .is_none_or(|provider| provider.filter_completions());
 5602
 5603        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5604            if filter_completions {
 5605                menu.filter(query.clone(), provider.clone(), window, cx);
 5606            }
 5607            // When `is_incomplete` is false, no need to re-query completions when the current query
 5608            // is a suffix of the initial query.
 5609            if !menu.is_incomplete {
 5610                // If the new query is a suffix of the old query (typing more characters) and
 5611                // the previous result was complete, the existing completions can be filtered.
 5612                //
 5613                // Note that this is always true for snippet completions.
 5614                let query_matches = match (&menu.initial_query, &query) {
 5615                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5616                    (None, _) => true,
 5617                    _ => false,
 5618                };
 5619                if query_matches {
 5620                    let position_matches = if menu.initial_position == position {
 5621                        true
 5622                    } else {
 5623                        let snapshot = self.buffer.read(cx).read(cx);
 5624                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5625                    };
 5626                    if position_matches {
 5627                        return;
 5628                    }
 5629                }
 5630            }
 5631        };
 5632
 5633        let trigger_kind = match trigger {
 5634            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5635                CompletionTriggerKind::TRIGGER_CHARACTER
 5636            }
 5637            _ => CompletionTriggerKind::INVOKED,
 5638        };
 5639        let completion_context = CompletionContext {
 5640            trigger_character: trigger.and_then(|trigger| {
 5641                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5642                    Some(String::from(trigger))
 5643                } else {
 5644                    None
 5645                }
 5646            }),
 5647            trigger_kind,
 5648        };
 5649
 5650        let Anchor {
 5651            excerpt_id: buffer_excerpt_id,
 5652            text_anchor: buffer_position,
 5653            ..
 5654        } = buffer_position;
 5655
 5656        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5657            buffer_snapshot.surrounding_word(buffer_position, None)
 5658        {
 5659            let word_to_exclude = buffer_snapshot
 5660                .text_for_range(word_range.clone())
 5661                .collect::<String>();
 5662            (
 5663                buffer_snapshot.anchor_before(word_range.start)
 5664                    ..buffer_snapshot.anchor_after(buffer_position),
 5665                Some(word_to_exclude),
 5666            )
 5667        } else {
 5668            (buffer_position..buffer_position, None)
 5669        };
 5670
 5671        let language = buffer_snapshot
 5672            .language_at(buffer_position)
 5673            .map(|language| language.name());
 5674
 5675        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5676            .completions
 5677            .clone();
 5678
 5679        let show_completion_documentation = buffer_snapshot
 5680            .settings_at(buffer_position, cx)
 5681            .show_completion_documentation;
 5682
 5683        // The document can be large, so stay in reasonable bounds when searching for words,
 5684        // otherwise completion pop-up might be slow to appear.
 5685        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5686        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5687        let min_word_search = buffer_snapshot.clip_point(
 5688            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5689            Bias::Left,
 5690        );
 5691        let max_word_search = buffer_snapshot.clip_point(
 5692            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5693            Bias::Right,
 5694        );
 5695        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5696            ..buffer_snapshot.point_to_offset(max_word_search);
 5697
 5698        let skip_digits = query
 5699            .as_ref()
 5700            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5701
 5702        let omit_word_completions = !self.word_completions_enabled
 5703            || (!ignore_word_threshold
 5704                && match &query {
 5705                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5706                    None => completion_settings.words_min_length != 0,
 5707                });
 5708
 5709        let (mut words, provider_responses) = match &provider {
 5710            Some(provider) => {
 5711                let provider_responses = provider.completions(
 5712                    buffer_excerpt_id,
 5713                    &buffer,
 5714                    buffer_position,
 5715                    completion_context,
 5716                    window,
 5717                    cx,
 5718                );
 5719
 5720                let words = match (omit_word_completions, completion_settings.words) {
 5721                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5722                        Task::ready(BTreeMap::default())
 5723                    }
 5724                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5725                        .background_spawn(async move {
 5726                            buffer_snapshot.words_in_range(WordsQuery {
 5727                                fuzzy_contents: None,
 5728                                range: word_search_range,
 5729                                skip_digits,
 5730                            })
 5731                        }),
 5732                };
 5733
 5734                (words, provider_responses)
 5735            }
 5736            None => {
 5737                let words = if omit_word_completions {
 5738                    Task::ready(BTreeMap::default())
 5739                } else {
 5740                    cx.background_spawn(async move {
 5741                        buffer_snapshot.words_in_range(WordsQuery {
 5742                            fuzzy_contents: None,
 5743                            range: word_search_range,
 5744                            skip_digits,
 5745                        })
 5746                    })
 5747                };
 5748                (words, Task::ready(Ok(Vec::new())))
 5749            }
 5750        };
 5751
 5752        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5753
 5754        let id = post_inc(&mut self.next_completion_id);
 5755        let task = cx.spawn_in(window, async move |editor, cx| {
 5756            let Ok(()) = editor.update(cx, |this, _| {
 5757                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5758            }) else {
 5759                return;
 5760            };
 5761
 5762            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5763            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5764            let mut completions = Vec::new();
 5765            let mut is_incomplete = false;
 5766            let mut display_options: Option<CompletionDisplayOptions> = None;
 5767            if let Some(provider_responses) = provider_responses.await.log_err()
 5768                && !provider_responses.is_empty()
 5769            {
 5770                for response in provider_responses {
 5771                    completions.extend(response.completions);
 5772                    is_incomplete = is_incomplete || response.is_incomplete;
 5773                    match display_options.as_mut() {
 5774                        None => {
 5775                            display_options = Some(response.display_options);
 5776                        }
 5777                        Some(options) => options.merge(&response.display_options),
 5778                    }
 5779                }
 5780                if completion_settings.words == WordsCompletionMode::Fallback {
 5781                    words = Task::ready(BTreeMap::default());
 5782                }
 5783            }
 5784            let display_options = display_options.unwrap_or_default();
 5785
 5786            let mut words = words.await;
 5787            if let Some(word_to_exclude) = &word_to_exclude {
 5788                words.remove(word_to_exclude);
 5789            }
 5790            for lsp_completion in &completions {
 5791                words.remove(&lsp_completion.new_text);
 5792            }
 5793            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5794                replace_range: word_replace_range.clone(),
 5795                new_text: word.clone(),
 5796                label: CodeLabel::plain(word, None),
 5797                icon_path: None,
 5798                documentation: None,
 5799                source: CompletionSource::BufferWord {
 5800                    word_range,
 5801                    resolved: false,
 5802                },
 5803                insert_text_mode: Some(InsertTextMode::AS_IS),
 5804                confirm: None,
 5805            }));
 5806
 5807            let menu = if completions.is_empty() {
 5808                None
 5809            } else {
 5810                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5811                    let languages = editor
 5812                        .workspace
 5813                        .as_ref()
 5814                        .and_then(|(workspace, _)| workspace.upgrade())
 5815                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5816                    let menu = CompletionsMenu::new(
 5817                        id,
 5818                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5819                        sort_completions,
 5820                        show_completion_documentation,
 5821                        position,
 5822                        query.clone(),
 5823                        is_incomplete,
 5824                        buffer.clone(),
 5825                        completions.into(),
 5826                        display_options,
 5827                        snippet_sort_order,
 5828                        languages,
 5829                        language,
 5830                        cx,
 5831                    );
 5832
 5833                    let query = if filter_completions { query } else { None };
 5834                    let matches_task = if let Some(query) = query {
 5835                        menu.do_async_filtering(query, cx)
 5836                    } else {
 5837                        Task::ready(menu.unfiltered_matches())
 5838                    };
 5839                    (menu, matches_task)
 5840                }) else {
 5841                    return;
 5842                };
 5843
 5844                let matches = matches_task.await;
 5845
 5846                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5847                    // Newer menu already set, so exit.
 5848                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5849                        editor.context_menu.borrow().as_ref()
 5850                        && prev_menu.id > id
 5851                    {
 5852                        return;
 5853                    };
 5854
 5855                    // Only valid to take prev_menu because it the new menu is immediately set
 5856                    // below, or the menu is hidden.
 5857                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5858                        editor.context_menu.borrow_mut().take()
 5859                    {
 5860                        let position_matches =
 5861                            if prev_menu.initial_position == menu.initial_position {
 5862                                true
 5863                            } else {
 5864                                let snapshot = editor.buffer.read(cx).read(cx);
 5865                                prev_menu.initial_position.to_offset(&snapshot)
 5866                                    == menu.initial_position.to_offset(&snapshot)
 5867                            };
 5868                        if position_matches {
 5869                            // Preserve markdown cache before `set_filter_results` because it will
 5870                            // try to populate the documentation cache.
 5871                            menu.preserve_markdown_cache(prev_menu);
 5872                        }
 5873                    };
 5874
 5875                    menu.set_filter_results(matches, provider, window, cx);
 5876                }) else {
 5877                    return;
 5878                };
 5879
 5880                menu.visible().then_some(menu)
 5881            };
 5882
 5883            editor
 5884                .update_in(cx, |editor, window, cx| {
 5885                    if editor.focus_handle.is_focused(window)
 5886                        && let Some(menu) = menu
 5887                    {
 5888                        *editor.context_menu.borrow_mut() =
 5889                            Some(CodeContextMenu::Completions(menu));
 5890
 5891                        crate::hover_popover::hide_hover(editor, cx);
 5892                        if editor.show_edit_predictions_in_menu() {
 5893                            editor.update_visible_edit_prediction(window, cx);
 5894                        } else {
 5895                            editor.discard_edit_prediction(false, cx);
 5896                        }
 5897
 5898                        cx.notify();
 5899                        return;
 5900                    }
 5901
 5902                    if editor.completion_tasks.len() <= 1 {
 5903                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5904                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5905                        // If it was already hidden and we don't show edit predictions in the menu,
 5906                        // we should also show the edit prediction when available.
 5907                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5908                            editor.update_visible_edit_prediction(window, cx);
 5909                        }
 5910                    }
 5911                })
 5912                .ok();
 5913        });
 5914
 5915        self.completion_tasks.push((id, task));
 5916    }
 5917
 5918    #[cfg(feature = "test-support")]
 5919    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5920        let menu = self.context_menu.borrow();
 5921        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5922            let completions = menu.completions.borrow();
 5923            Some(completions.to_vec())
 5924        } else {
 5925            None
 5926        }
 5927    }
 5928
 5929    pub fn with_completions_menu_matching_id<R>(
 5930        &self,
 5931        id: CompletionId,
 5932        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5933    ) -> R {
 5934        let mut context_menu = self.context_menu.borrow_mut();
 5935        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5936            return f(None);
 5937        };
 5938        if completions_menu.id != id {
 5939            return f(None);
 5940        }
 5941        f(Some(completions_menu))
 5942    }
 5943
 5944    pub fn confirm_completion(
 5945        &mut self,
 5946        action: &ConfirmCompletion,
 5947        window: &mut Window,
 5948        cx: &mut Context<Self>,
 5949    ) -> Option<Task<Result<()>>> {
 5950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5951        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5952    }
 5953
 5954    pub fn confirm_completion_insert(
 5955        &mut self,
 5956        _: &ConfirmCompletionInsert,
 5957        window: &mut Window,
 5958        cx: &mut Context<Self>,
 5959    ) -> Option<Task<Result<()>>> {
 5960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5961        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5962    }
 5963
 5964    pub fn confirm_completion_replace(
 5965        &mut self,
 5966        _: &ConfirmCompletionReplace,
 5967        window: &mut Window,
 5968        cx: &mut Context<Self>,
 5969    ) -> Option<Task<Result<()>>> {
 5970        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5971        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5972    }
 5973
 5974    pub fn compose_completion(
 5975        &mut self,
 5976        action: &ComposeCompletion,
 5977        window: &mut Window,
 5978        cx: &mut Context<Self>,
 5979    ) -> Option<Task<Result<()>>> {
 5980        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5981        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5982    }
 5983
 5984    fn do_completion(
 5985        &mut self,
 5986        item_ix: Option<usize>,
 5987        intent: CompletionIntent,
 5988        window: &mut Window,
 5989        cx: &mut Context<Editor>,
 5990    ) -> Option<Task<Result<()>>> {
 5991        use language::ToOffset as _;
 5992
 5993        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5994        else {
 5995            return None;
 5996        };
 5997
 5998        let candidate_id = {
 5999            let entries = completions_menu.entries.borrow();
 6000            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6001            if self.show_edit_predictions_in_menu() {
 6002                self.discard_edit_prediction(true, cx);
 6003            }
 6004            mat.candidate_id
 6005        };
 6006
 6007        let completion = completions_menu
 6008            .completions
 6009            .borrow()
 6010            .get(candidate_id)?
 6011            .clone();
 6012        cx.stop_propagation();
 6013
 6014        let buffer_handle = completions_menu.buffer.clone();
 6015
 6016        let CompletionEdit {
 6017            new_text,
 6018            snippet,
 6019            replace_range,
 6020        } = process_completion_for_edit(
 6021            &completion,
 6022            intent,
 6023            &buffer_handle,
 6024            &completions_menu.initial_position.text_anchor,
 6025            cx,
 6026        );
 6027
 6028        let buffer = buffer_handle.read(cx);
 6029        let snapshot = self.buffer.read(cx).snapshot(cx);
 6030        let newest_anchor = self.selections.newest_anchor();
 6031        let replace_range_multibuffer = {
 6032            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6033            excerpt.map_range_from_buffer(replace_range.clone())
 6034        };
 6035        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6036            return None;
 6037        }
 6038
 6039        let old_text = buffer
 6040            .text_for_range(replace_range.clone())
 6041            .collect::<String>();
 6042        let lookbehind = newest_anchor
 6043            .start
 6044            .text_anchor
 6045            .to_offset(buffer)
 6046            .saturating_sub(replace_range.start);
 6047        let lookahead = replace_range
 6048            .end
 6049            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6050        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6051        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6052
 6053        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6054        let mut ranges = Vec::new();
 6055        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6056
 6057        for selection in &selections {
 6058            let range = if selection.id == newest_anchor.id {
 6059                replace_range_multibuffer.clone()
 6060            } else {
 6061                let mut range = selection.range();
 6062
 6063                // if prefix is present, don't duplicate it
 6064                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6065                    range.start = range.start.saturating_sub(lookbehind);
 6066
 6067                    // if suffix is also present, mimic the newest cursor and replace it
 6068                    if selection.id != newest_anchor.id
 6069                        && snapshot.contains_str_at(range.end, suffix)
 6070                    {
 6071                        range.end += lookahead;
 6072                    }
 6073                }
 6074                range
 6075            };
 6076
 6077            ranges.push(range.clone());
 6078
 6079            if !self.linked_edit_ranges.is_empty() {
 6080                let start_anchor = snapshot.anchor_before(range.start);
 6081                let end_anchor = snapshot.anchor_after(range.end);
 6082                if let Some(ranges) = self
 6083                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6084                {
 6085                    for (buffer, edits) in ranges {
 6086                        linked_edits
 6087                            .entry(buffer.clone())
 6088                            .or_default()
 6089                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6090                    }
 6091                }
 6092            }
 6093        }
 6094
 6095        let common_prefix_len = old_text
 6096            .chars()
 6097            .zip(new_text.chars())
 6098            .take_while(|(a, b)| a == b)
 6099            .map(|(a, _)| a.len_utf8())
 6100            .sum::<usize>();
 6101
 6102        cx.emit(EditorEvent::InputHandled {
 6103            utf16_range_to_replace: None,
 6104            text: new_text[common_prefix_len..].into(),
 6105        });
 6106
 6107        self.transact(window, cx, |editor, window, cx| {
 6108            if let Some(mut snippet) = snippet {
 6109                snippet.text = new_text.to_string();
 6110                editor
 6111                    .insert_snippet(&ranges, snippet, window, cx)
 6112                    .log_err();
 6113            } else {
 6114                editor.buffer.update(cx, |multi_buffer, cx| {
 6115                    let auto_indent = match completion.insert_text_mode {
 6116                        Some(InsertTextMode::AS_IS) => None,
 6117                        _ => editor.autoindent_mode.clone(),
 6118                    };
 6119                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6120                    multi_buffer.edit(edits, auto_indent, cx);
 6121                });
 6122            }
 6123            for (buffer, edits) in linked_edits {
 6124                buffer.update(cx, |buffer, cx| {
 6125                    let snapshot = buffer.snapshot();
 6126                    let edits = edits
 6127                        .into_iter()
 6128                        .map(|(range, text)| {
 6129                            use text::ToPoint as TP;
 6130                            let end_point = TP::to_point(&range.end, &snapshot);
 6131                            let start_point = TP::to_point(&range.start, &snapshot);
 6132                            (start_point..end_point, text)
 6133                        })
 6134                        .sorted_by_key(|(range, _)| range.start);
 6135                    buffer.edit(edits, None, cx);
 6136                })
 6137            }
 6138
 6139            editor.refresh_edit_prediction(true, false, window, cx);
 6140        });
 6141        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6142
 6143        let show_new_completions_on_confirm = completion
 6144            .confirm
 6145            .as_ref()
 6146            .is_some_and(|confirm| confirm(intent, window, cx));
 6147        if show_new_completions_on_confirm {
 6148            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6149        }
 6150
 6151        let provider = self.completion_provider.as_ref()?;
 6152        drop(completion);
 6153        let apply_edits = provider.apply_additional_edits_for_completion(
 6154            buffer_handle,
 6155            completions_menu.completions.clone(),
 6156            candidate_id,
 6157            true,
 6158            cx,
 6159        );
 6160
 6161        let editor_settings = EditorSettings::get_global(cx);
 6162        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6163            // After the code completion is finished, users often want to know what signatures are needed.
 6164            // so we should automatically call signature_help
 6165            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6166        }
 6167
 6168        Some(cx.foreground_executor().spawn(async move {
 6169            apply_edits.await?;
 6170            Ok(())
 6171        }))
 6172    }
 6173
 6174    pub fn toggle_code_actions(
 6175        &mut self,
 6176        action: &ToggleCodeActions,
 6177        window: &mut Window,
 6178        cx: &mut Context<Self>,
 6179    ) {
 6180        let quick_launch = action.quick_launch;
 6181        let mut context_menu = self.context_menu.borrow_mut();
 6182        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6183            if code_actions.deployed_from == action.deployed_from {
 6184                // Toggle if we're selecting the same one
 6185                *context_menu = None;
 6186                cx.notify();
 6187                return;
 6188            } else {
 6189                // Otherwise, clear it and start a new one
 6190                *context_menu = None;
 6191                cx.notify();
 6192            }
 6193        }
 6194        drop(context_menu);
 6195        let snapshot = self.snapshot(window, cx);
 6196        let deployed_from = action.deployed_from.clone();
 6197        let action = action.clone();
 6198        self.completion_tasks.clear();
 6199        self.discard_edit_prediction(false, cx);
 6200
 6201        let multibuffer_point = match &action.deployed_from {
 6202            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6203                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6204            }
 6205            _ => self
 6206                .selections
 6207                .newest::<Point>(&snapshot.display_snapshot)
 6208                .head(),
 6209        };
 6210        let Some((buffer, buffer_row)) = snapshot
 6211            .buffer_snapshot()
 6212            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6213            .and_then(|(buffer_snapshot, range)| {
 6214                self.buffer()
 6215                    .read(cx)
 6216                    .buffer(buffer_snapshot.remote_id())
 6217                    .map(|buffer| (buffer, range.start.row))
 6218            })
 6219        else {
 6220            return;
 6221        };
 6222        let buffer_id = buffer.read(cx).remote_id();
 6223        let tasks = self
 6224            .tasks
 6225            .get(&(buffer_id, buffer_row))
 6226            .map(|t| Arc::new(t.to_owned()));
 6227
 6228        if !self.focus_handle.is_focused(window) {
 6229            return;
 6230        }
 6231        let project = self.project.clone();
 6232
 6233        let code_actions_task = match deployed_from {
 6234            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6235            _ => self.code_actions(buffer_row, window, cx),
 6236        };
 6237
 6238        let runnable_task = match deployed_from {
 6239            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6240            _ => {
 6241                let mut task_context_task = Task::ready(None);
 6242                if let Some(tasks) = &tasks
 6243                    && let Some(project) = project
 6244                {
 6245                    task_context_task =
 6246                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6247                }
 6248
 6249                cx.spawn_in(window, {
 6250                    let buffer = buffer.clone();
 6251                    async move |editor, cx| {
 6252                        let task_context = task_context_task.await;
 6253
 6254                        let resolved_tasks =
 6255                            tasks
 6256                                .zip(task_context.clone())
 6257                                .map(|(tasks, task_context)| ResolvedTasks {
 6258                                    templates: tasks.resolve(&task_context).collect(),
 6259                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6260                                        multibuffer_point.row,
 6261                                        tasks.column,
 6262                                    )),
 6263                                });
 6264                        let debug_scenarios = editor
 6265                            .update(cx, |editor, cx| {
 6266                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6267                            })?
 6268                            .await;
 6269                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6270                    }
 6271                })
 6272            }
 6273        };
 6274
 6275        cx.spawn_in(window, async move |editor, cx| {
 6276            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6277            let code_actions = code_actions_task.await;
 6278            let spawn_straight_away = quick_launch
 6279                && resolved_tasks
 6280                    .as_ref()
 6281                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6282                && code_actions
 6283                    .as_ref()
 6284                    .is_none_or(|actions| actions.is_empty())
 6285                && debug_scenarios.is_empty();
 6286
 6287            editor.update_in(cx, |editor, window, cx| {
 6288                crate::hover_popover::hide_hover(editor, cx);
 6289                let actions = CodeActionContents::new(
 6290                    resolved_tasks,
 6291                    code_actions,
 6292                    debug_scenarios,
 6293                    task_context.unwrap_or_default(),
 6294                );
 6295
 6296                // Don't show the menu if there are no actions available
 6297                if actions.is_empty() {
 6298                    cx.notify();
 6299                    return Task::ready(Ok(()));
 6300                }
 6301
 6302                *editor.context_menu.borrow_mut() =
 6303                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6304                        buffer,
 6305                        actions,
 6306                        selected_item: Default::default(),
 6307                        scroll_handle: UniformListScrollHandle::default(),
 6308                        deployed_from,
 6309                    }));
 6310                cx.notify();
 6311                if spawn_straight_away
 6312                    && let Some(task) = editor.confirm_code_action(
 6313                        &ConfirmCodeAction { item_ix: Some(0) },
 6314                        window,
 6315                        cx,
 6316                    )
 6317                {
 6318                    return task;
 6319                }
 6320
 6321                Task::ready(Ok(()))
 6322            })
 6323        })
 6324        .detach_and_log_err(cx);
 6325    }
 6326
 6327    fn debug_scenarios(
 6328        &mut self,
 6329        resolved_tasks: &Option<ResolvedTasks>,
 6330        buffer: &Entity<Buffer>,
 6331        cx: &mut App,
 6332    ) -> Task<Vec<task::DebugScenario>> {
 6333        maybe!({
 6334            let project = self.project()?;
 6335            let dap_store = project.read(cx).dap_store();
 6336            let mut scenarios = vec![];
 6337            let resolved_tasks = resolved_tasks.as_ref()?;
 6338            let buffer = buffer.read(cx);
 6339            let language = buffer.language()?;
 6340            let file = buffer.file();
 6341            let debug_adapter = language_settings(language.name().into(), file, cx)
 6342                .debuggers
 6343                .first()
 6344                .map(SharedString::from)
 6345                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6346
 6347            dap_store.update(cx, |dap_store, cx| {
 6348                for (_, task) in &resolved_tasks.templates {
 6349                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6350                        task.original_task().clone(),
 6351                        debug_adapter.clone().into(),
 6352                        task.display_label().to_owned().into(),
 6353                        cx,
 6354                    );
 6355                    scenarios.push(maybe_scenario);
 6356                }
 6357            });
 6358            Some(cx.background_spawn(async move {
 6359                futures::future::join_all(scenarios)
 6360                    .await
 6361                    .into_iter()
 6362                    .flatten()
 6363                    .collect::<Vec<_>>()
 6364            }))
 6365        })
 6366        .unwrap_or_else(|| Task::ready(vec![]))
 6367    }
 6368
 6369    fn code_actions(
 6370        &mut self,
 6371        buffer_row: u32,
 6372        window: &mut Window,
 6373        cx: &mut Context<Self>,
 6374    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6375        let mut task = self.code_actions_task.take();
 6376        cx.spawn_in(window, async move |editor, cx| {
 6377            while let Some(prev_task) = task {
 6378                prev_task.await.log_err();
 6379                task = editor
 6380                    .update(cx, |this, _| this.code_actions_task.take())
 6381                    .ok()?;
 6382            }
 6383
 6384            editor
 6385                .update(cx, |editor, cx| {
 6386                    editor
 6387                        .available_code_actions
 6388                        .clone()
 6389                        .and_then(|(location, code_actions)| {
 6390                            let snapshot = location.buffer.read(cx).snapshot();
 6391                            let point_range = location.range.to_point(&snapshot);
 6392                            let point_range = point_range.start.row..=point_range.end.row;
 6393                            if point_range.contains(&buffer_row) {
 6394                                Some(code_actions)
 6395                            } else {
 6396                                None
 6397                            }
 6398                        })
 6399                })
 6400                .ok()
 6401                .flatten()
 6402        })
 6403    }
 6404
 6405    pub fn confirm_code_action(
 6406        &mut self,
 6407        action: &ConfirmCodeAction,
 6408        window: &mut Window,
 6409        cx: &mut Context<Self>,
 6410    ) -> Option<Task<Result<()>>> {
 6411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6412
 6413        let actions_menu =
 6414            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6415                menu
 6416            } else {
 6417                return None;
 6418            };
 6419
 6420        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6421        let action = actions_menu.actions.get(action_ix)?;
 6422        let title = action.label();
 6423        let buffer = actions_menu.buffer;
 6424        let workspace = self.workspace()?;
 6425
 6426        match action {
 6427            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6428                workspace.update(cx, |workspace, cx| {
 6429                    workspace.schedule_resolved_task(
 6430                        task_source_kind,
 6431                        resolved_task,
 6432                        false,
 6433                        window,
 6434                        cx,
 6435                    );
 6436
 6437                    Some(Task::ready(Ok(())))
 6438                })
 6439            }
 6440            CodeActionsItem::CodeAction {
 6441                excerpt_id,
 6442                action,
 6443                provider,
 6444            } => {
 6445                let apply_code_action =
 6446                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6447                let workspace = workspace.downgrade();
 6448                Some(cx.spawn_in(window, async move |editor, cx| {
 6449                    let project_transaction = apply_code_action.await?;
 6450                    Self::open_project_transaction(
 6451                        &editor,
 6452                        workspace,
 6453                        project_transaction,
 6454                        title,
 6455                        cx,
 6456                    )
 6457                    .await
 6458                }))
 6459            }
 6460            CodeActionsItem::DebugScenario(scenario) => {
 6461                let context = actions_menu.actions.context;
 6462
 6463                workspace.update(cx, |workspace, cx| {
 6464                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6465                    workspace.start_debug_session(
 6466                        scenario,
 6467                        context,
 6468                        Some(buffer),
 6469                        None,
 6470                        window,
 6471                        cx,
 6472                    );
 6473                });
 6474                Some(Task::ready(Ok(())))
 6475            }
 6476        }
 6477    }
 6478
 6479    pub async fn open_project_transaction(
 6480        editor: &WeakEntity<Editor>,
 6481        workspace: WeakEntity<Workspace>,
 6482        transaction: ProjectTransaction,
 6483        title: String,
 6484        cx: &mut AsyncWindowContext,
 6485    ) -> Result<()> {
 6486        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6487        cx.update(|_, cx| {
 6488            entries.sort_unstable_by_key(|(buffer, _)| {
 6489                buffer.read(cx).file().map(|f| f.path().clone())
 6490            });
 6491        })?;
 6492        if entries.is_empty() {
 6493            return Ok(());
 6494        }
 6495
 6496        // If the project transaction's edits are all contained within this editor, then
 6497        // avoid opening a new editor to display them.
 6498
 6499        if let [(buffer, transaction)] = &*entries {
 6500            let excerpt = editor.update(cx, |editor, cx| {
 6501                editor
 6502                    .buffer()
 6503                    .read(cx)
 6504                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6505            })?;
 6506            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6507                && excerpted_buffer == *buffer
 6508            {
 6509                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6510                    let excerpt_range = excerpt_range.to_offset(buffer);
 6511                    buffer
 6512                        .edited_ranges_for_transaction::<usize>(transaction)
 6513                        .all(|range| {
 6514                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6515                        })
 6516                })?;
 6517
 6518                if all_edits_within_excerpt {
 6519                    return Ok(());
 6520                }
 6521            }
 6522        }
 6523
 6524        let mut ranges_to_highlight = Vec::new();
 6525        let excerpt_buffer = cx.new(|cx| {
 6526            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6527            for (buffer_handle, transaction) in &entries {
 6528                let edited_ranges = buffer_handle
 6529                    .read(cx)
 6530                    .edited_ranges_for_transaction::<Point>(transaction)
 6531                    .collect::<Vec<_>>();
 6532                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6533                    PathKey::for_buffer(buffer_handle, cx),
 6534                    buffer_handle.clone(),
 6535                    edited_ranges,
 6536                    multibuffer_context_lines(cx),
 6537                    cx,
 6538                );
 6539
 6540                ranges_to_highlight.extend(ranges);
 6541            }
 6542            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6543            multibuffer
 6544        })?;
 6545
 6546        workspace.update_in(cx, |workspace, window, cx| {
 6547            let project = workspace.project().clone();
 6548            let editor =
 6549                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6550            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6551            editor.update(cx, |editor, cx| {
 6552                editor.highlight_background::<Self>(
 6553                    &ranges_to_highlight,
 6554                    |theme| theme.colors().editor_highlighted_line_background,
 6555                    cx,
 6556                );
 6557            });
 6558        })?;
 6559
 6560        Ok(())
 6561    }
 6562
 6563    pub fn clear_code_action_providers(&mut self) {
 6564        self.code_action_providers.clear();
 6565        self.available_code_actions.take();
 6566    }
 6567
 6568    pub fn add_code_action_provider(
 6569        &mut self,
 6570        provider: Rc<dyn CodeActionProvider>,
 6571        window: &mut Window,
 6572        cx: &mut Context<Self>,
 6573    ) {
 6574        if self
 6575            .code_action_providers
 6576            .iter()
 6577            .any(|existing_provider| existing_provider.id() == provider.id())
 6578        {
 6579            return;
 6580        }
 6581
 6582        self.code_action_providers.push(provider);
 6583        self.refresh_code_actions(window, cx);
 6584    }
 6585
 6586    pub fn remove_code_action_provider(
 6587        &mut self,
 6588        id: Arc<str>,
 6589        window: &mut Window,
 6590        cx: &mut Context<Self>,
 6591    ) {
 6592        self.code_action_providers
 6593            .retain(|provider| provider.id() != id);
 6594        self.refresh_code_actions(window, cx);
 6595    }
 6596
 6597    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6598        !self.code_action_providers.is_empty()
 6599            && EditorSettings::get_global(cx).toolbar.code_actions
 6600    }
 6601
 6602    pub fn has_available_code_actions(&self) -> bool {
 6603        self.available_code_actions
 6604            .as_ref()
 6605            .is_some_and(|(_, actions)| !actions.is_empty())
 6606    }
 6607
 6608    fn render_inline_code_actions(
 6609        &self,
 6610        icon_size: ui::IconSize,
 6611        display_row: DisplayRow,
 6612        is_active: bool,
 6613        cx: &mut Context<Self>,
 6614    ) -> AnyElement {
 6615        let show_tooltip = !self.context_menu_visible();
 6616        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6617            .icon_size(icon_size)
 6618            .shape(ui::IconButtonShape::Square)
 6619            .icon_color(ui::Color::Hidden)
 6620            .toggle_state(is_active)
 6621            .when(show_tooltip, |this| {
 6622                this.tooltip({
 6623                    let focus_handle = self.focus_handle.clone();
 6624                    move |window, cx| {
 6625                        Tooltip::for_action_in(
 6626                            "Toggle Code Actions",
 6627                            &ToggleCodeActions {
 6628                                deployed_from: None,
 6629                                quick_launch: false,
 6630                            },
 6631                            &focus_handle,
 6632                            window,
 6633                            cx,
 6634                        )
 6635                    }
 6636                })
 6637            })
 6638            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6639                window.focus(&editor.focus_handle(cx));
 6640                editor.toggle_code_actions(
 6641                    &crate::actions::ToggleCodeActions {
 6642                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6643                            display_row,
 6644                        )),
 6645                        quick_launch: false,
 6646                    },
 6647                    window,
 6648                    cx,
 6649                );
 6650            }))
 6651            .into_any_element()
 6652    }
 6653
 6654    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6655        &self.context_menu
 6656    }
 6657
 6658    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6659        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6660            cx.background_executor()
 6661                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6662                .await;
 6663
 6664            let (start_buffer, start, _, end, newest_selection) = this
 6665                .update(cx, |this, cx| {
 6666                    let newest_selection = this.selections.newest_anchor().clone();
 6667                    if newest_selection.head().diff_base_anchor.is_some() {
 6668                        return None;
 6669                    }
 6670                    let display_snapshot = this.display_snapshot(cx);
 6671                    let newest_selection_adjusted =
 6672                        this.selections.newest_adjusted(&display_snapshot);
 6673                    let buffer = this.buffer.read(cx);
 6674
 6675                    let (start_buffer, start) =
 6676                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6677                    let (end_buffer, end) =
 6678                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6679
 6680                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6681                })?
 6682                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6683                .context(
 6684                    "Expected selection to lie in a single buffer when refreshing code actions",
 6685                )?;
 6686            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6687                let providers = this.code_action_providers.clone();
 6688                let tasks = this
 6689                    .code_action_providers
 6690                    .iter()
 6691                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6692                    .collect::<Vec<_>>();
 6693                (providers, tasks)
 6694            })?;
 6695
 6696            let mut actions = Vec::new();
 6697            for (provider, provider_actions) in
 6698                providers.into_iter().zip(future::join_all(tasks).await)
 6699            {
 6700                if let Some(provider_actions) = provider_actions.log_err() {
 6701                    actions.extend(provider_actions.into_iter().map(|action| {
 6702                        AvailableCodeAction {
 6703                            excerpt_id: newest_selection.start.excerpt_id,
 6704                            action,
 6705                            provider: provider.clone(),
 6706                        }
 6707                    }));
 6708                }
 6709            }
 6710
 6711            this.update(cx, |this, cx| {
 6712                this.available_code_actions = if actions.is_empty() {
 6713                    None
 6714                } else {
 6715                    Some((
 6716                        Location {
 6717                            buffer: start_buffer,
 6718                            range: start..end,
 6719                        },
 6720                        actions.into(),
 6721                    ))
 6722                };
 6723                cx.notify();
 6724            })
 6725        }));
 6726    }
 6727
 6728    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6729        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6730            self.show_git_blame_inline = false;
 6731
 6732            self.show_git_blame_inline_delay_task =
 6733                Some(cx.spawn_in(window, async move |this, cx| {
 6734                    cx.background_executor().timer(delay).await;
 6735
 6736                    this.update(cx, |this, cx| {
 6737                        this.show_git_blame_inline = true;
 6738                        cx.notify();
 6739                    })
 6740                    .log_err();
 6741                }));
 6742        }
 6743    }
 6744
 6745    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6746        let snapshot = self.snapshot(window, cx);
 6747        let cursor = self
 6748            .selections
 6749            .newest::<Point>(&snapshot.display_snapshot)
 6750            .head();
 6751        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6752        else {
 6753            return;
 6754        };
 6755
 6756        let Some(blame) = self.blame.as_ref() else {
 6757            return;
 6758        };
 6759
 6760        let row_info = RowInfo {
 6761            buffer_id: Some(buffer.remote_id()),
 6762            buffer_row: Some(point.row),
 6763            ..Default::default()
 6764        };
 6765        let Some((buffer, blame_entry)) = blame
 6766            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6767            .flatten()
 6768        else {
 6769            return;
 6770        };
 6771
 6772        let anchor = self.selections.newest_anchor().head();
 6773        let position = self.to_pixel_point(anchor, &snapshot, window);
 6774        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6775            self.show_blame_popover(
 6776                buffer,
 6777                &blame_entry,
 6778                position + last_bounds.origin,
 6779                true,
 6780                cx,
 6781            );
 6782        };
 6783    }
 6784
 6785    fn show_blame_popover(
 6786        &mut self,
 6787        buffer: BufferId,
 6788        blame_entry: &BlameEntry,
 6789        position: gpui::Point<Pixels>,
 6790        ignore_timeout: bool,
 6791        cx: &mut Context<Self>,
 6792    ) {
 6793        if let Some(state) = &mut self.inline_blame_popover {
 6794            state.hide_task.take();
 6795        } else {
 6796            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6797            let blame_entry = blame_entry.clone();
 6798            let show_task = cx.spawn(async move |editor, cx| {
 6799                if !ignore_timeout {
 6800                    cx.background_executor()
 6801                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6802                        .await;
 6803                }
 6804                editor
 6805                    .update(cx, |editor, cx| {
 6806                        editor.inline_blame_popover_show_task.take();
 6807                        let Some(blame) = editor.blame.as_ref() else {
 6808                            return;
 6809                        };
 6810                        let blame = blame.read(cx);
 6811                        let details = blame.details_for_entry(buffer, &blame_entry);
 6812                        let markdown = cx.new(|cx| {
 6813                            Markdown::new(
 6814                                details
 6815                                    .as_ref()
 6816                                    .map(|message| message.message.clone())
 6817                                    .unwrap_or_default(),
 6818                                None,
 6819                                None,
 6820                                cx,
 6821                            )
 6822                        });
 6823                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6824                            position,
 6825                            hide_task: None,
 6826                            popover_bounds: None,
 6827                            popover_state: InlineBlamePopoverState {
 6828                                scroll_handle: ScrollHandle::new(),
 6829                                commit_message: details,
 6830                                markdown,
 6831                            },
 6832                            keyboard_grace: ignore_timeout,
 6833                        });
 6834                        cx.notify();
 6835                    })
 6836                    .ok();
 6837            });
 6838            self.inline_blame_popover_show_task = Some(show_task);
 6839        }
 6840    }
 6841
 6842    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6843        self.inline_blame_popover_show_task.take();
 6844        if let Some(state) = &mut self.inline_blame_popover {
 6845            let hide_task = cx.spawn(async move |editor, cx| {
 6846                cx.background_executor()
 6847                    .timer(std::time::Duration::from_millis(100))
 6848                    .await;
 6849                editor
 6850                    .update(cx, |editor, cx| {
 6851                        editor.inline_blame_popover.take();
 6852                        cx.notify();
 6853                    })
 6854                    .ok();
 6855            });
 6856            state.hide_task = Some(hide_task);
 6857        }
 6858    }
 6859
 6860    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6861        if self.pending_rename.is_some() {
 6862            return None;
 6863        }
 6864
 6865        let provider = self.semantics_provider.clone()?;
 6866        let buffer = self.buffer.read(cx);
 6867        let newest_selection = self.selections.newest_anchor().clone();
 6868        let cursor_position = newest_selection.head();
 6869        let (cursor_buffer, cursor_buffer_position) =
 6870            buffer.text_anchor_for_position(cursor_position, cx)?;
 6871        let (tail_buffer, tail_buffer_position) =
 6872            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6873        if cursor_buffer != tail_buffer {
 6874            return None;
 6875        }
 6876
 6877        let snapshot = cursor_buffer.read(cx).snapshot();
 6878        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6879        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6880        if start_word_range != end_word_range {
 6881            self.document_highlights_task.take();
 6882            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6883            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6884            return None;
 6885        }
 6886
 6887        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6888        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6889            cx.background_executor()
 6890                .timer(Duration::from_millis(debounce))
 6891                .await;
 6892
 6893            let highlights = if let Some(highlights) = cx
 6894                .update(|cx| {
 6895                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6896                })
 6897                .ok()
 6898                .flatten()
 6899            {
 6900                highlights.await.log_err()
 6901            } else {
 6902                None
 6903            };
 6904
 6905            if let Some(highlights) = highlights {
 6906                this.update(cx, |this, cx| {
 6907                    if this.pending_rename.is_some() {
 6908                        return;
 6909                    }
 6910
 6911                    let buffer = this.buffer.read(cx);
 6912                    if buffer
 6913                        .text_anchor_for_position(cursor_position, cx)
 6914                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6915                    {
 6916                        return;
 6917                    }
 6918
 6919                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6920                    let mut write_ranges = Vec::new();
 6921                    let mut read_ranges = Vec::new();
 6922                    for highlight in highlights {
 6923                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6924                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6925                        {
 6926                            let start = highlight
 6927                                .range
 6928                                .start
 6929                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6930                            let end = highlight
 6931                                .range
 6932                                .end
 6933                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6934                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6935                                continue;
 6936                            }
 6937
 6938                            let range =
 6939                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6940                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6941                                write_ranges.push(range);
 6942                            } else {
 6943                                read_ranges.push(range);
 6944                            }
 6945                        }
 6946                    }
 6947
 6948                    this.highlight_background::<DocumentHighlightRead>(
 6949                        &read_ranges,
 6950                        |theme| theme.colors().editor_document_highlight_read_background,
 6951                        cx,
 6952                    );
 6953                    this.highlight_background::<DocumentHighlightWrite>(
 6954                        &write_ranges,
 6955                        |theme| theme.colors().editor_document_highlight_write_background,
 6956                        cx,
 6957                    );
 6958                    cx.notify();
 6959                })
 6960                .log_err();
 6961            }
 6962        }));
 6963        None
 6964    }
 6965
 6966    fn prepare_highlight_query_from_selection(
 6967        &mut self,
 6968        cx: &mut Context<Editor>,
 6969    ) -> Option<(String, Range<Anchor>)> {
 6970        if matches!(self.mode, EditorMode::SingleLine) {
 6971            return None;
 6972        }
 6973        if !EditorSettings::get_global(cx).selection_highlight {
 6974            return None;
 6975        }
 6976        if self.selections.count() != 1 || self.selections.line_mode() {
 6977            return None;
 6978        }
 6979        let selection = self.selections.newest_anchor();
 6980        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6981        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6982            ..selection.end.to_point(&multi_buffer_snapshot);
 6983        // If the selection spans multiple rows OR it is empty
 6984        if selection_point_range.start.row != selection_point_range.end.row
 6985            || selection_point_range.start.column == selection_point_range.end.column
 6986        {
 6987            return None;
 6988        }
 6989
 6990        let query = multi_buffer_snapshot
 6991            .text_for_range(selection.range())
 6992            .collect::<String>();
 6993        if query.trim().is_empty() {
 6994            return None;
 6995        }
 6996        Some((query, selection.range()))
 6997    }
 6998
 6999    fn update_selection_occurrence_highlights(
 7000        &mut self,
 7001        query_text: String,
 7002        query_range: Range<Anchor>,
 7003        multi_buffer_range_to_query: Range<Point>,
 7004        use_debounce: bool,
 7005        window: &mut Window,
 7006        cx: &mut Context<Editor>,
 7007    ) -> Task<()> {
 7008        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7009        cx.spawn_in(window, async move |editor, cx| {
 7010            if use_debounce {
 7011                cx.background_executor()
 7012                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7013                    .await;
 7014            }
 7015            let match_task = cx.background_spawn(async move {
 7016                let buffer_ranges = multi_buffer_snapshot
 7017                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7018                    .into_iter()
 7019                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7020                let mut match_ranges = Vec::new();
 7021                let Ok(regex) = project::search::SearchQuery::text(
 7022                    query_text.clone(),
 7023                    false,
 7024                    false,
 7025                    false,
 7026                    Default::default(),
 7027                    Default::default(),
 7028                    false,
 7029                    None,
 7030                ) else {
 7031                    return Vec::default();
 7032                };
 7033                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7034                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7035                    match_ranges.extend(
 7036                        regex
 7037                            .search(buffer_snapshot, Some(search_range.clone()))
 7038                            .await
 7039                            .into_iter()
 7040                            .filter_map(|match_range| {
 7041                                let match_start = buffer_snapshot
 7042                                    .anchor_after(search_range.start + match_range.start);
 7043                                let match_end = buffer_snapshot
 7044                                    .anchor_before(search_range.start + match_range.end);
 7045                                let match_anchor_range = Anchor::range_in_buffer(
 7046                                    excerpt_id,
 7047                                    buffer_snapshot.remote_id(),
 7048                                    match_start..match_end,
 7049                                );
 7050                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7051                            }),
 7052                    );
 7053                }
 7054                match_ranges
 7055            });
 7056            let match_ranges = match_task.await;
 7057            editor
 7058                .update_in(cx, |editor, _, cx| {
 7059                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7060                    if !match_ranges.is_empty() {
 7061                        editor.highlight_background::<SelectedTextHighlight>(
 7062                            &match_ranges,
 7063                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7064                            cx,
 7065                        )
 7066                    }
 7067                })
 7068                .log_err();
 7069        })
 7070    }
 7071
 7072    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7073        struct NewlineFold;
 7074        let type_id = std::any::TypeId::of::<NewlineFold>();
 7075        if !self.mode.is_single_line() {
 7076            return;
 7077        }
 7078        let snapshot = self.snapshot(window, cx);
 7079        if snapshot.buffer_snapshot().max_point().row == 0 {
 7080            return;
 7081        }
 7082        let task = cx.background_spawn(async move {
 7083            let new_newlines = snapshot
 7084                .buffer_chars_at(0)
 7085                .filter_map(|(c, i)| {
 7086                    if c == '\n' {
 7087                        Some(
 7088                            snapshot.buffer_snapshot().anchor_after(i)
 7089                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7090                        )
 7091                    } else {
 7092                        None
 7093                    }
 7094                })
 7095                .collect::<Vec<_>>();
 7096            let existing_newlines = snapshot
 7097                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7098                .filter_map(|fold| {
 7099                    if fold.placeholder.type_tag == Some(type_id) {
 7100                        Some(fold.range.start..fold.range.end)
 7101                    } else {
 7102                        None
 7103                    }
 7104                })
 7105                .collect::<Vec<_>>();
 7106
 7107            (new_newlines, existing_newlines)
 7108        });
 7109        self.folding_newlines = cx.spawn(async move |this, cx| {
 7110            let (new_newlines, existing_newlines) = task.await;
 7111            if new_newlines == existing_newlines {
 7112                return;
 7113            }
 7114            let placeholder = FoldPlaceholder {
 7115                render: Arc::new(move |_, _, cx| {
 7116                    div()
 7117                        .bg(cx.theme().status().hint_background)
 7118                        .border_b_1()
 7119                        .size_full()
 7120                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7121                        .border_color(cx.theme().status().hint)
 7122                        .child("\\n")
 7123                        .into_any()
 7124                }),
 7125                constrain_width: false,
 7126                merge_adjacent: false,
 7127                type_tag: Some(type_id),
 7128            };
 7129            let creases = new_newlines
 7130                .into_iter()
 7131                .map(|range| Crease::simple(range, placeholder.clone()))
 7132                .collect();
 7133            this.update(cx, |this, cx| {
 7134                this.display_map.update(cx, |display_map, cx| {
 7135                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7136                    display_map.fold(creases, cx);
 7137                });
 7138            })
 7139            .ok();
 7140        });
 7141    }
 7142
 7143    fn refresh_selected_text_highlights(
 7144        &mut self,
 7145        on_buffer_edit: bool,
 7146        window: &mut Window,
 7147        cx: &mut Context<Editor>,
 7148    ) {
 7149        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7150        else {
 7151            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7152            self.quick_selection_highlight_task.take();
 7153            self.debounced_selection_highlight_task.take();
 7154            return;
 7155        };
 7156        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7157        if on_buffer_edit
 7158            || self
 7159                .quick_selection_highlight_task
 7160                .as_ref()
 7161                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7162        {
 7163            let multi_buffer_visible_start = self
 7164                .scroll_manager
 7165                .anchor()
 7166                .anchor
 7167                .to_point(&multi_buffer_snapshot);
 7168            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7169                multi_buffer_visible_start
 7170                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7171                Bias::Left,
 7172            );
 7173            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7174            self.quick_selection_highlight_task = Some((
 7175                query_range.clone(),
 7176                self.update_selection_occurrence_highlights(
 7177                    query_text.clone(),
 7178                    query_range.clone(),
 7179                    multi_buffer_visible_range,
 7180                    false,
 7181                    window,
 7182                    cx,
 7183                ),
 7184            ));
 7185        }
 7186        if on_buffer_edit
 7187            || self
 7188                .debounced_selection_highlight_task
 7189                .as_ref()
 7190                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7191        {
 7192            let multi_buffer_start = multi_buffer_snapshot
 7193                .anchor_before(0)
 7194                .to_point(&multi_buffer_snapshot);
 7195            let multi_buffer_end = multi_buffer_snapshot
 7196                .anchor_after(multi_buffer_snapshot.len())
 7197                .to_point(&multi_buffer_snapshot);
 7198            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7199            self.debounced_selection_highlight_task = Some((
 7200                query_range.clone(),
 7201                self.update_selection_occurrence_highlights(
 7202                    query_text,
 7203                    query_range,
 7204                    multi_buffer_full_range,
 7205                    true,
 7206                    window,
 7207                    cx,
 7208                ),
 7209            ));
 7210        }
 7211    }
 7212
 7213    pub fn refresh_edit_prediction(
 7214        &mut self,
 7215        debounce: bool,
 7216        user_requested: bool,
 7217        window: &mut Window,
 7218        cx: &mut Context<Self>,
 7219    ) -> Option<()> {
 7220        if DisableAiSettings::get_global(cx).disable_ai {
 7221            return None;
 7222        }
 7223
 7224        let provider = self.edit_prediction_provider()?;
 7225        let cursor = self.selections.newest_anchor().head();
 7226        let (buffer, cursor_buffer_position) =
 7227            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7228
 7229        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7230            self.discard_edit_prediction(false, cx);
 7231            return None;
 7232        }
 7233
 7234        self.update_visible_edit_prediction(window, cx);
 7235
 7236        if !user_requested
 7237            && (!self.should_show_edit_predictions()
 7238                || !self.is_focused(window)
 7239                || buffer.read(cx).is_empty())
 7240        {
 7241            self.discard_edit_prediction(false, cx);
 7242            return None;
 7243        }
 7244
 7245        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7246        Some(())
 7247    }
 7248
 7249    fn show_edit_predictions_in_menu(&self) -> bool {
 7250        match self.edit_prediction_settings {
 7251            EditPredictionSettings::Disabled => false,
 7252            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7253        }
 7254    }
 7255
 7256    pub fn edit_predictions_enabled(&self) -> bool {
 7257        match self.edit_prediction_settings {
 7258            EditPredictionSettings::Disabled => false,
 7259            EditPredictionSettings::Enabled { .. } => true,
 7260        }
 7261    }
 7262
 7263    fn edit_prediction_requires_modifier(&self) -> bool {
 7264        match self.edit_prediction_settings {
 7265            EditPredictionSettings::Disabled => false,
 7266            EditPredictionSettings::Enabled {
 7267                preview_requires_modifier,
 7268                ..
 7269            } => preview_requires_modifier,
 7270        }
 7271    }
 7272
 7273    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7274        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7275            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7276            self.discard_edit_prediction(false, cx);
 7277        } else {
 7278            let selection = self.selections.newest_anchor();
 7279            let cursor = selection.head();
 7280
 7281            if let Some((buffer, cursor_buffer_position)) =
 7282                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7283            {
 7284                self.edit_prediction_settings =
 7285                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7286            }
 7287        }
 7288    }
 7289
 7290    fn edit_prediction_settings_at_position(
 7291        &self,
 7292        buffer: &Entity<Buffer>,
 7293        buffer_position: language::Anchor,
 7294        cx: &App,
 7295    ) -> EditPredictionSettings {
 7296        if !self.mode.is_full()
 7297            || !self.show_edit_predictions_override.unwrap_or(true)
 7298            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7299        {
 7300            return EditPredictionSettings::Disabled;
 7301        }
 7302
 7303        let buffer = buffer.read(cx);
 7304
 7305        let file = buffer.file();
 7306
 7307        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7308            return EditPredictionSettings::Disabled;
 7309        };
 7310
 7311        let by_provider = matches!(
 7312            self.menu_edit_predictions_policy,
 7313            MenuEditPredictionsPolicy::ByProvider
 7314        );
 7315
 7316        let show_in_menu = by_provider
 7317            && self
 7318                .edit_prediction_provider
 7319                .as_ref()
 7320                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7321
 7322        let preview_requires_modifier =
 7323            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7324
 7325        EditPredictionSettings::Enabled {
 7326            show_in_menu,
 7327            preview_requires_modifier,
 7328        }
 7329    }
 7330
 7331    fn should_show_edit_predictions(&self) -> bool {
 7332        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7333    }
 7334
 7335    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7336        matches!(
 7337            self.edit_prediction_preview,
 7338            EditPredictionPreview::Active { .. }
 7339        )
 7340    }
 7341
 7342    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7343        let cursor = self.selections.newest_anchor().head();
 7344        if let Some((buffer, cursor_position)) =
 7345            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7346        {
 7347            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7348        } else {
 7349            false
 7350        }
 7351    }
 7352
 7353    pub fn supports_minimap(&self, cx: &App) -> bool {
 7354        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7355    }
 7356
 7357    fn edit_predictions_enabled_in_buffer(
 7358        &self,
 7359        buffer: &Entity<Buffer>,
 7360        buffer_position: language::Anchor,
 7361        cx: &App,
 7362    ) -> bool {
 7363        maybe!({
 7364            if self.read_only(cx) {
 7365                return Some(false);
 7366            }
 7367            let provider = self.edit_prediction_provider()?;
 7368            if !provider.is_enabled(buffer, buffer_position, cx) {
 7369                return Some(false);
 7370            }
 7371            let buffer = buffer.read(cx);
 7372            let Some(file) = buffer.file() else {
 7373                return Some(true);
 7374            };
 7375            let settings = all_language_settings(Some(file), cx);
 7376            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7377        })
 7378        .unwrap_or(false)
 7379    }
 7380
 7381    fn cycle_edit_prediction(
 7382        &mut self,
 7383        direction: Direction,
 7384        window: &mut Window,
 7385        cx: &mut Context<Self>,
 7386    ) -> Option<()> {
 7387        let provider = self.edit_prediction_provider()?;
 7388        let cursor = self.selections.newest_anchor().head();
 7389        let (buffer, cursor_buffer_position) =
 7390            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7391        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7392            return None;
 7393        }
 7394
 7395        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7396        self.update_visible_edit_prediction(window, cx);
 7397
 7398        Some(())
 7399    }
 7400
 7401    pub fn show_edit_prediction(
 7402        &mut self,
 7403        _: &ShowEditPrediction,
 7404        window: &mut Window,
 7405        cx: &mut Context<Self>,
 7406    ) {
 7407        if !self.has_active_edit_prediction() {
 7408            self.refresh_edit_prediction(false, true, window, cx);
 7409            return;
 7410        }
 7411
 7412        self.update_visible_edit_prediction(window, cx);
 7413    }
 7414
 7415    pub fn display_cursor_names(
 7416        &mut self,
 7417        _: &DisplayCursorNames,
 7418        window: &mut Window,
 7419        cx: &mut Context<Self>,
 7420    ) {
 7421        self.show_cursor_names(window, cx);
 7422    }
 7423
 7424    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7425        self.show_cursor_names = true;
 7426        cx.notify();
 7427        cx.spawn_in(window, async move |this, cx| {
 7428            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7429            this.update(cx, |this, cx| {
 7430                this.show_cursor_names = false;
 7431                cx.notify()
 7432            })
 7433            .ok()
 7434        })
 7435        .detach();
 7436    }
 7437
 7438    pub fn next_edit_prediction(
 7439        &mut self,
 7440        _: &NextEditPrediction,
 7441        window: &mut Window,
 7442        cx: &mut Context<Self>,
 7443    ) {
 7444        if self.has_active_edit_prediction() {
 7445            self.cycle_edit_prediction(Direction::Next, window, cx);
 7446        } else {
 7447            let is_copilot_disabled = self
 7448                .refresh_edit_prediction(false, true, window, cx)
 7449                .is_none();
 7450            if is_copilot_disabled {
 7451                cx.propagate();
 7452            }
 7453        }
 7454    }
 7455
 7456    pub fn previous_edit_prediction(
 7457        &mut self,
 7458        _: &PreviousEditPrediction,
 7459        window: &mut Window,
 7460        cx: &mut Context<Self>,
 7461    ) {
 7462        if self.has_active_edit_prediction() {
 7463            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7464        } else {
 7465            let is_copilot_disabled = self
 7466                .refresh_edit_prediction(false, true, window, cx)
 7467                .is_none();
 7468            if is_copilot_disabled {
 7469                cx.propagate();
 7470            }
 7471        }
 7472    }
 7473
 7474    pub fn accept_edit_prediction(
 7475        &mut self,
 7476        _: &AcceptEditPrediction,
 7477        window: &mut Window,
 7478        cx: &mut Context<Self>,
 7479    ) {
 7480        if self.show_edit_predictions_in_menu() {
 7481            self.hide_context_menu(window, cx);
 7482        }
 7483
 7484        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7485            return;
 7486        };
 7487
 7488        match &active_edit_prediction.completion {
 7489            EditPrediction::MoveWithin { target, .. } => {
 7490                let target = *target;
 7491
 7492                if let Some(position_map) = &self.last_position_map {
 7493                    if position_map
 7494                        .visible_row_range
 7495                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7496                        || !self.edit_prediction_requires_modifier()
 7497                    {
 7498                        self.unfold_ranges(&[target..target], true, false, cx);
 7499                        // Note that this is also done in vim's handler of the Tab action.
 7500                        self.change_selections(
 7501                            SelectionEffects::scroll(Autoscroll::newest()),
 7502                            window,
 7503                            cx,
 7504                            |selections| {
 7505                                selections.select_anchor_ranges([target..target]);
 7506                            },
 7507                        );
 7508                        self.clear_row_highlights::<EditPredictionPreview>();
 7509
 7510                        self.edit_prediction_preview
 7511                            .set_previous_scroll_position(None);
 7512                    } else {
 7513                        self.edit_prediction_preview
 7514                            .set_previous_scroll_position(Some(
 7515                                position_map.snapshot.scroll_anchor,
 7516                            ));
 7517
 7518                        self.highlight_rows::<EditPredictionPreview>(
 7519                            target..target,
 7520                            cx.theme().colors().editor_highlighted_line_background,
 7521                            RowHighlightOptions {
 7522                                autoscroll: true,
 7523                                ..Default::default()
 7524                            },
 7525                            cx,
 7526                        );
 7527                        self.request_autoscroll(Autoscroll::fit(), cx);
 7528                    }
 7529                }
 7530            }
 7531            EditPrediction::MoveOutside { snapshot, target } => {
 7532                if let Some(workspace) = self.workspace() {
 7533                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7534                        .detach_and_log_err(cx);
 7535                }
 7536            }
 7537            EditPrediction::Edit { edits, .. } => {
 7538                self.report_edit_prediction_event(
 7539                    active_edit_prediction.completion_id.clone(),
 7540                    true,
 7541                    cx,
 7542                );
 7543
 7544                if let Some(provider) = self.edit_prediction_provider() {
 7545                    provider.accept(cx);
 7546                }
 7547
 7548                // Store the transaction ID and selections before applying the edit
 7549                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7550
 7551                let snapshot = self.buffer.read(cx).snapshot(cx);
 7552                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7553
 7554                self.buffer.update(cx, |buffer, cx| {
 7555                    buffer.edit(edits.iter().cloned(), None, cx)
 7556                });
 7557
 7558                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7559                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7560                });
 7561
 7562                let selections = self.selections.disjoint_anchors_arc();
 7563                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7564                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7565                    if has_new_transaction {
 7566                        self.selection_history
 7567                            .insert_transaction(transaction_id_now, selections);
 7568                    }
 7569                }
 7570
 7571                self.update_visible_edit_prediction(window, cx);
 7572                if self.active_edit_prediction.is_none() {
 7573                    self.refresh_edit_prediction(true, true, window, cx);
 7574                }
 7575
 7576                cx.notify();
 7577            }
 7578        }
 7579
 7580        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7581    }
 7582
 7583    pub fn accept_partial_edit_prediction(
 7584        &mut self,
 7585        _: &AcceptPartialEditPrediction,
 7586        window: &mut Window,
 7587        cx: &mut Context<Self>,
 7588    ) {
 7589        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7590            return;
 7591        };
 7592        if self.selections.count() != 1 {
 7593            return;
 7594        }
 7595
 7596        match &active_edit_prediction.completion {
 7597            EditPrediction::MoveWithin { target, .. } => {
 7598                let target = *target;
 7599                self.change_selections(
 7600                    SelectionEffects::scroll(Autoscroll::newest()),
 7601                    window,
 7602                    cx,
 7603                    |selections| {
 7604                        selections.select_anchor_ranges([target..target]);
 7605                    },
 7606                );
 7607            }
 7608            EditPrediction::MoveOutside { snapshot, target } => {
 7609                if let Some(workspace) = self.workspace() {
 7610                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7611                        .detach_and_log_err(cx);
 7612                }
 7613            }
 7614            EditPrediction::Edit { edits, .. } => {
 7615                self.report_edit_prediction_event(
 7616                    active_edit_prediction.completion_id.clone(),
 7617                    true,
 7618                    cx,
 7619                );
 7620
 7621                // Find an insertion that starts at the cursor position.
 7622                let snapshot = self.buffer.read(cx).snapshot(cx);
 7623                let cursor_offset = self
 7624                    .selections
 7625                    .newest::<usize>(&self.display_snapshot(cx))
 7626                    .head();
 7627                let insertion = edits.iter().find_map(|(range, text)| {
 7628                    let range = range.to_offset(&snapshot);
 7629                    if range.is_empty() && range.start == cursor_offset {
 7630                        Some(text)
 7631                    } else {
 7632                        None
 7633                    }
 7634                });
 7635
 7636                if let Some(text) = insertion {
 7637                    let mut partial_completion = text
 7638                        .chars()
 7639                        .by_ref()
 7640                        .take_while(|c| c.is_alphabetic())
 7641                        .collect::<String>();
 7642                    if partial_completion.is_empty() {
 7643                        partial_completion = text
 7644                            .chars()
 7645                            .by_ref()
 7646                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7647                            .collect::<String>();
 7648                    }
 7649
 7650                    cx.emit(EditorEvent::InputHandled {
 7651                        utf16_range_to_replace: None,
 7652                        text: partial_completion.clone().into(),
 7653                    });
 7654
 7655                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7656
 7657                    self.refresh_edit_prediction(true, true, window, cx);
 7658                    cx.notify();
 7659                } else {
 7660                    self.accept_edit_prediction(&Default::default(), window, cx);
 7661                }
 7662            }
 7663        }
 7664    }
 7665
 7666    fn discard_edit_prediction(
 7667        &mut self,
 7668        should_report_edit_prediction_event: bool,
 7669        cx: &mut Context<Self>,
 7670    ) -> bool {
 7671        if should_report_edit_prediction_event {
 7672            let completion_id = self
 7673                .active_edit_prediction
 7674                .as_ref()
 7675                .and_then(|active_completion| active_completion.completion_id.clone());
 7676
 7677            self.report_edit_prediction_event(completion_id, false, cx);
 7678        }
 7679
 7680        if let Some(provider) = self.edit_prediction_provider() {
 7681            provider.discard(cx);
 7682        }
 7683
 7684        self.take_active_edit_prediction(cx)
 7685    }
 7686
 7687    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7688        let Some(provider) = self.edit_prediction_provider() else {
 7689            return;
 7690        };
 7691
 7692        let Some((_, buffer, _)) = self
 7693            .buffer
 7694            .read(cx)
 7695            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7696        else {
 7697            return;
 7698        };
 7699
 7700        let extension = buffer
 7701            .read(cx)
 7702            .file()
 7703            .and_then(|file| Some(file.path().extension()?.to_string()));
 7704
 7705        let event_type = match accepted {
 7706            true => "Edit Prediction Accepted",
 7707            false => "Edit Prediction Discarded",
 7708        };
 7709        telemetry::event!(
 7710            event_type,
 7711            provider = provider.name(),
 7712            prediction_id = id,
 7713            suggestion_accepted = accepted,
 7714            file_extension = extension,
 7715        );
 7716    }
 7717
 7718    fn open_editor_at_anchor(
 7719        snapshot: &language::BufferSnapshot,
 7720        target: language::Anchor,
 7721        workspace: &Entity<Workspace>,
 7722        window: &mut Window,
 7723        cx: &mut App,
 7724    ) -> Task<Result<()>> {
 7725        workspace.update(cx, |workspace, cx| {
 7726            let path = snapshot.file().map(|file| file.full_path(cx));
 7727            let Some(path) =
 7728                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7729            else {
 7730                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7731            };
 7732            let target = text::ToPoint::to_point(&target, snapshot);
 7733            let item = workspace.open_path(path, None, true, window, cx);
 7734            window.spawn(cx, async move |cx| {
 7735                let Some(editor) = item.await?.downcast::<Editor>() else {
 7736                    return Ok(());
 7737                };
 7738                editor
 7739                    .update_in(cx, |editor, window, cx| {
 7740                        editor.go_to_singleton_buffer_point(target, window, cx);
 7741                    })
 7742                    .ok();
 7743                anyhow::Ok(())
 7744            })
 7745        })
 7746    }
 7747
 7748    pub fn has_active_edit_prediction(&self) -> bool {
 7749        self.active_edit_prediction.is_some()
 7750    }
 7751
 7752    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7753        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7754            return false;
 7755        };
 7756
 7757        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7758        self.clear_highlights::<EditPredictionHighlight>(cx);
 7759        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7760        true
 7761    }
 7762
 7763    /// Returns true when we're displaying the edit prediction popover below the cursor
 7764    /// like we are not previewing and the LSP autocomplete menu is visible
 7765    /// or we are in `when_holding_modifier` mode.
 7766    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7767        if self.edit_prediction_preview_is_active()
 7768            || !self.show_edit_predictions_in_menu()
 7769            || !self.edit_predictions_enabled()
 7770        {
 7771            return false;
 7772        }
 7773
 7774        if self.has_visible_completions_menu() {
 7775            return true;
 7776        }
 7777
 7778        has_completion && self.edit_prediction_requires_modifier()
 7779    }
 7780
 7781    fn handle_modifiers_changed(
 7782        &mut self,
 7783        modifiers: Modifiers,
 7784        position_map: &PositionMap,
 7785        window: &mut Window,
 7786        cx: &mut Context<Self>,
 7787    ) {
 7788        if self.show_edit_predictions_in_menu() {
 7789            self.update_edit_prediction_preview(&modifiers, window, cx);
 7790        }
 7791
 7792        self.update_selection_mode(&modifiers, position_map, window, cx);
 7793
 7794        let mouse_position = window.mouse_position();
 7795        if !position_map.text_hitbox.is_hovered(window) {
 7796            return;
 7797        }
 7798
 7799        self.update_hovered_link(
 7800            position_map.point_for_position(mouse_position),
 7801            &position_map.snapshot,
 7802            modifiers,
 7803            window,
 7804            cx,
 7805        )
 7806    }
 7807
 7808    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7809        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7810        if invert {
 7811            match multi_cursor_setting {
 7812                MultiCursorModifier::Alt => modifiers.alt,
 7813                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7814            }
 7815        } else {
 7816            match multi_cursor_setting {
 7817                MultiCursorModifier::Alt => modifiers.secondary(),
 7818                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7819            }
 7820        }
 7821    }
 7822
 7823    fn columnar_selection_mode(
 7824        modifiers: &Modifiers,
 7825        cx: &mut Context<Self>,
 7826    ) -> Option<ColumnarMode> {
 7827        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7828            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7829                Some(ColumnarMode::FromMouse)
 7830            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7831                Some(ColumnarMode::FromSelection)
 7832            } else {
 7833                None
 7834            }
 7835        } else {
 7836            None
 7837        }
 7838    }
 7839
 7840    fn update_selection_mode(
 7841        &mut self,
 7842        modifiers: &Modifiers,
 7843        position_map: &PositionMap,
 7844        window: &mut Window,
 7845        cx: &mut Context<Self>,
 7846    ) {
 7847        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7848            return;
 7849        };
 7850        if self.selections.pending_anchor().is_none() {
 7851            return;
 7852        }
 7853
 7854        let mouse_position = window.mouse_position();
 7855        let point_for_position = position_map.point_for_position(mouse_position);
 7856        let position = point_for_position.previous_valid;
 7857
 7858        self.select(
 7859            SelectPhase::BeginColumnar {
 7860                position,
 7861                reset: false,
 7862                mode,
 7863                goal_column: point_for_position.exact_unclipped.column(),
 7864            },
 7865            window,
 7866            cx,
 7867        );
 7868    }
 7869
 7870    fn update_edit_prediction_preview(
 7871        &mut self,
 7872        modifiers: &Modifiers,
 7873        window: &mut Window,
 7874        cx: &mut Context<Self>,
 7875    ) {
 7876        let mut modifiers_held = false;
 7877        if let Some(accept_keystroke) = self
 7878            .accept_edit_prediction_keybind(false, window, cx)
 7879            .keystroke()
 7880        {
 7881            modifiers_held = modifiers_held
 7882                || (accept_keystroke.modifiers() == modifiers
 7883                    && accept_keystroke.modifiers().modified());
 7884        };
 7885        if let Some(accept_partial_keystroke) = self
 7886            .accept_edit_prediction_keybind(true, window, cx)
 7887            .keystroke()
 7888        {
 7889            modifiers_held = modifiers_held
 7890                || (accept_partial_keystroke.modifiers() == modifiers
 7891                    && accept_partial_keystroke.modifiers().modified());
 7892        }
 7893
 7894        if modifiers_held {
 7895            if matches!(
 7896                self.edit_prediction_preview,
 7897                EditPredictionPreview::Inactive { .. }
 7898            ) {
 7899                self.edit_prediction_preview = EditPredictionPreview::Active {
 7900                    previous_scroll_position: None,
 7901                    since: Instant::now(),
 7902                };
 7903
 7904                self.update_visible_edit_prediction(window, cx);
 7905                cx.notify();
 7906            }
 7907        } else if let EditPredictionPreview::Active {
 7908            previous_scroll_position,
 7909            since,
 7910        } = self.edit_prediction_preview
 7911        {
 7912            if let (Some(previous_scroll_position), Some(position_map)) =
 7913                (previous_scroll_position, self.last_position_map.as_ref())
 7914            {
 7915                self.set_scroll_position(
 7916                    previous_scroll_position
 7917                        .scroll_position(&position_map.snapshot.display_snapshot),
 7918                    window,
 7919                    cx,
 7920                );
 7921            }
 7922
 7923            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7924                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7925            };
 7926            self.clear_row_highlights::<EditPredictionPreview>();
 7927            self.update_visible_edit_prediction(window, cx);
 7928            cx.notify();
 7929        }
 7930    }
 7931
 7932    fn update_visible_edit_prediction(
 7933        &mut self,
 7934        _window: &mut Window,
 7935        cx: &mut Context<Self>,
 7936    ) -> Option<()> {
 7937        if DisableAiSettings::get_global(cx).disable_ai {
 7938            return None;
 7939        }
 7940
 7941        if self.ime_transaction.is_some() {
 7942            self.discard_edit_prediction(false, cx);
 7943            return None;
 7944        }
 7945
 7946        let selection = self.selections.newest_anchor();
 7947        let cursor = selection.head();
 7948        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7949        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7950        let excerpt_id = cursor.excerpt_id;
 7951
 7952        let show_in_menu = self.show_edit_predictions_in_menu();
 7953        let completions_menu_has_precedence = !show_in_menu
 7954            && (self.context_menu.borrow().is_some()
 7955                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7956
 7957        if completions_menu_has_precedence
 7958            || !offset_selection.is_empty()
 7959            || self
 7960                .active_edit_prediction
 7961                .as_ref()
 7962                .is_some_and(|completion| {
 7963                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7964                        return false;
 7965                    };
 7966                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7967                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7968                    !invalidation_range.contains(&offset_selection.head())
 7969                })
 7970        {
 7971            self.discard_edit_prediction(false, cx);
 7972            return None;
 7973        }
 7974
 7975        self.take_active_edit_prediction(cx);
 7976        let Some(provider) = self.edit_prediction_provider() else {
 7977            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7978            return None;
 7979        };
 7980
 7981        let (buffer, cursor_buffer_position) =
 7982            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7983
 7984        self.edit_prediction_settings =
 7985            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7986
 7987        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7988
 7989        if self.edit_prediction_indent_conflict {
 7990            let cursor_point = cursor.to_point(&multibuffer);
 7991
 7992            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7993
 7994            if let Some((_, indent)) = indents.iter().next()
 7995                && indent.len == cursor_point.column
 7996            {
 7997                self.edit_prediction_indent_conflict = false;
 7998            }
 7999        }
 8000
 8001        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8002
 8003        let (completion_id, edits, edit_preview) = match edit_prediction {
 8004            edit_prediction::EditPrediction::Local {
 8005                id,
 8006                edits,
 8007                edit_preview,
 8008            } => (id, edits, edit_preview),
 8009            edit_prediction::EditPrediction::Jump {
 8010                id,
 8011                snapshot,
 8012                target,
 8013            } => {
 8014                self.stale_edit_prediction_in_menu = None;
 8015                self.active_edit_prediction = Some(EditPredictionState {
 8016                    inlay_ids: vec![],
 8017                    completion: EditPrediction::MoveOutside { snapshot, target },
 8018                    completion_id: id,
 8019                    invalidation_range: None,
 8020                });
 8021                cx.notify();
 8022                return Some(());
 8023            }
 8024        };
 8025
 8026        let edits = edits
 8027            .into_iter()
 8028            .flat_map(|(range, new_text)| {
 8029                Some((
 8030                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8031                    new_text,
 8032                ))
 8033            })
 8034            .collect::<Vec<_>>();
 8035        if edits.is_empty() {
 8036            return None;
 8037        }
 8038
 8039        let first_edit_start = edits.first().unwrap().0.start;
 8040        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8041        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8042
 8043        let last_edit_end = edits.last().unwrap().0.end;
 8044        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8045        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8046
 8047        let cursor_row = cursor.to_point(&multibuffer).row;
 8048
 8049        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8050
 8051        let mut inlay_ids = Vec::new();
 8052        let invalidation_row_range;
 8053        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8054            Some(cursor_row..edit_end_row)
 8055        } else if cursor_row > edit_end_row {
 8056            Some(edit_start_row..cursor_row)
 8057        } else {
 8058            None
 8059        };
 8060        let supports_jump = self
 8061            .edit_prediction_provider
 8062            .as_ref()
 8063            .map(|provider| provider.provider.supports_jump_to_edit())
 8064            .unwrap_or(true);
 8065
 8066        let is_move = supports_jump
 8067            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8068        let completion = if is_move {
 8069            invalidation_row_range =
 8070                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8071            let target = first_edit_start;
 8072            EditPrediction::MoveWithin { target, snapshot }
 8073        } else {
 8074            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8075                && !self.edit_predictions_hidden_for_vim_mode;
 8076
 8077            if show_completions_in_buffer {
 8078                if edits
 8079                    .iter()
 8080                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8081                {
 8082                    let mut inlays = Vec::new();
 8083                    for (range, new_text) in &edits {
 8084                        let inlay = Inlay::edit_prediction(
 8085                            post_inc(&mut self.next_inlay_id),
 8086                            range.start,
 8087                            new_text.as_str(),
 8088                        );
 8089                        inlay_ids.push(inlay.id);
 8090                        inlays.push(inlay);
 8091                    }
 8092
 8093                    self.splice_inlays(&[], inlays, cx);
 8094                } else {
 8095                    let background_color = cx.theme().status().deleted_background;
 8096                    self.highlight_text::<EditPredictionHighlight>(
 8097                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8098                        HighlightStyle {
 8099                            background_color: Some(background_color),
 8100                            ..Default::default()
 8101                        },
 8102                        cx,
 8103                    );
 8104                }
 8105            }
 8106
 8107            invalidation_row_range = edit_start_row..edit_end_row;
 8108
 8109            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8110                if provider.show_tab_accept_marker() {
 8111                    EditDisplayMode::TabAccept
 8112                } else {
 8113                    EditDisplayMode::Inline
 8114                }
 8115            } else {
 8116                EditDisplayMode::DiffPopover
 8117            };
 8118
 8119            EditPrediction::Edit {
 8120                edits,
 8121                edit_preview,
 8122                display_mode,
 8123                snapshot,
 8124            }
 8125        };
 8126
 8127        let invalidation_range = multibuffer
 8128            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8129            ..multibuffer.anchor_after(Point::new(
 8130                invalidation_row_range.end,
 8131                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8132            ));
 8133
 8134        self.stale_edit_prediction_in_menu = None;
 8135        self.active_edit_prediction = Some(EditPredictionState {
 8136            inlay_ids,
 8137            completion,
 8138            completion_id,
 8139            invalidation_range: Some(invalidation_range),
 8140        });
 8141
 8142        cx.notify();
 8143
 8144        Some(())
 8145    }
 8146
 8147    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8148        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8149    }
 8150
 8151    fn clear_tasks(&mut self) {
 8152        self.tasks.clear()
 8153    }
 8154
 8155    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8156        if self.tasks.insert(key, value).is_some() {
 8157            // This case should hopefully be rare, but just in case...
 8158            log::error!(
 8159                "multiple different run targets found on a single line, only the last target will be rendered"
 8160            )
 8161        }
 8162    }
 8163
 8164    /// Get all display points of breakpoints that will be rendered within editor
 8165    ///
 8166    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8167    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8168    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8169    fn active_breakpoints(
 8170        &self,
 8171        range: Range<DisplayRow>,
 8172        window: &mut Window,
 8173        cx: &mut Context<Self>,
 8174    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8175        let mut breakpoint_display_points = HashMap::default();
 8176
 8177        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8178            return breakpoint_display_points;
 8179        };
 8180
 8181        let snapshot = self.snapshot(window, cx);
 8182
 8183        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8184        let Some(project) = self.project() else {
 8185            return breakpoint_display_points;
 8186        };
 8187
 8188        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8189            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8190
 8191        for (buffer_snapshot, range, excerpt_id) in
 8192            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8193        {
 8194            let Some(buffer) = project
 8195                .read(cx)
 8196                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8197            else {
 8198                continue;
 8199            };
 8200            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8201                &buffer,
 8202                Some(
 8203                    buffer_snapshot.anchor_before(range.start)
 8204                        ..buffer_snapshot.anchor_after(range.end),
 8205                ),
 8206                buffer_snapshot,
 8207                cx,
 8208            );
 8209            for (breakpoint, state) in breakpoints {
 8210                let multi_buffer_anchor =
 8211                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8212                let position = multi_buffer_anchor
 8213                    .to_point(multi_buffer_snapshot)
 8214                    .to_display_point(&snapshot);
 8215
 8216                breakpoint_display_points.insert(
 8217                    position.row(),
 8218                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8219                );
 8220            }
 8221        }
 8222
 8223        breakpoint_display_points
 8224    }
 8225
 8226    fn breakpoint_context_menu(
 8227        &self,
 8228        anchor: Anchor,
 8229        window: &mut Window,
 8230        cx: &mut Context<Self>,
 8231    ) -> Entity<ui::ContextMenu> {
 8232        let weak_editor = cx.weak_entity();
 8233        let focus_handle = self.focus_handle(cx);
 8234
 8235        let row = self
 8236            .buffer
 8237            .read(cx)
 8238            .snapshot(cx)
 8239            .summary_for_anchor::<Point>(&anchor)
 8240            .row;
 8241
 8242        let breakpoint = self
 8243            .breakpoint_at_row(row, window, cx)
 8244            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8245
 8246        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8247            "Edit Log Breakpoint"
 8248        } else {
 8249            "Set Log Breakpoint"
 8250        };
 8251
 8252        let condition_breakpoint_msg = if breakpoint
 8253            .as_ref()
 8254            .is_some_and(|bp| bp.1.condition.is_some())
 8255        {
 8256            "Edit Condition Breakpoint"
 8257        } else {
 8258            "Set Condition Breakpoint"
 8259        };
 8260
 8261        let hit_condition_breakpoint_msg = if breakpoint
 8262            .as_ref()
 8263            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8264        {
 8265            "Edit Hit Condition Breakpoint"
 8266        } else {
 8267            "Set Hit Condition Breakpoint"
 8268        };
 8269
 8270        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8271            "Unset Breakpoint"
 8272        } else {
 8273            "Set Breakpoint"
 8274        };
 8275
 8276        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8277
 8278        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8279            BreakpointState::Enabled => Some("Disable"),
 8280            BreakpointState::Disabled => Some("Enable"),
 8281        });
 8282
 8283        let (anchor, breakpoint) =
 8284            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8285
 8286        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8287            menu.on_blur_subscription(Subscription::new(|| {}))
 8288                .context(focus_handle)
 8289                .when(run_to_cursor, |this| {
 8290                    let weak_editor = weak_editor.clone();
 8291                    this.entry("Run to cursor", None, move |window, cx| {
 8292                        weak_editor
 8293                            .update(cx, |editor, cx| {
 8294                                editor.change_selections(
 8295                                    SelectionEffects::no_scroll(),
 8296                                    window,
 8297                                    cx,
 8298                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8299                                );
 8300                            })
 8301                            .ok();
 8302
 8303                        window.dispatch_action(Box::new(RunToCursor), cx);
 8304                    })
 8305                    .separator()
 8306                })
 8307                .when_some(toggle_state_msg, |this, msg| {
 8308                    this.entry(msg, None, {
 8309                        let weak_editor = weak_editor.clone();
 8310                        let breakpoint = breakpoint.clone();
 8311                        move |_window, cx| {
 8312                            weak_editor
 8313                                .update(cx, |this, cx| {
 8314                                    this.edit_breakpoint_at_anchor(
 8315                                        anchor,
 8316                                        breakpoint.as_ref().clone(),
 8317                                        BreakpointEditAction::InvertState,
 8318                                        cx,
 8319                                    );
 8320                                })
 8321                                .log_err();
 8322                        }
 8323                    })
 8324                })
 8325                .entry(set_breakpoint_msg, None, {
 8326                    let weak_editor = weak_editor.clone();
 8327                    let breakpoint = breakpoint.clone();
 8328                    move |_window, cx| {
 8329                        weak_editor
 8330                            .update(cx, |this, cx| {
 8331                                this.edit_breakpoint_at_anchor(
 8332                                    anchor,
 8333                                    breakpoint.as_ref().clone(),
 8334                                    BreakpointEditAction::Toggle,
 8335                                    cx,
 8336                                );
 8337                            })
 8338                            .log_err();
 8339                    }
 8340                })
 8341                .entry(log_breakpoint_msg, None, {
 8342                    let breakpoint = breakpoint.clone();
 8343                    let weak_editor = weak_editor.clone();
 8344                    move |window, cx| {
 8345                        weak_editor
 8346                            .update(cx, |this, cx| {
 8347                                this.add_edit_breakpoint_block(
 8348                                    anchor,
 8349                                    breakpoint.as_ref(),
 8350                                    BreakpointPromptEditAction::Log,
 8351                                    window,
 8352                                    cx,
 8353                                );
 8354                            })
 8355                            .log_err();
 8356                    }
 8357                })
 8358                .entry(condition_breakpoint_msg, None, {
 8359                    let breakpoint = breakpoint.clone();
 8360                    let weak_editor = weak_editor.clone();
 8361                    move |window, cx| {
 8362                        weak_editor
 8363                            .update(cx, |this, cx| {
 8364                                this.add_edit_breakpoint_block(
 8365                                    anchor,
 8366                                    breakpoint.as_ref(),
 8367                                    BreakpointPromptEditAction::Condition,
 8368                                    window,
 8369                                    cx,
 8370                                );
 8371                            })
 8372                            .log_err();
 8373                    }
 8374                })
 8375                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8376                    weak_editor
 8377                        .update(cx, |this, cx| {
 8378                            this.add_edit_breakpoint_block(
 8379                                anchor,
 8380                                breakpoint.as_ref(),
 8381                                BreakpointPromptEditAction::HitCondition,
 8382                                window,
 8383                                cx,
 8384                            );
 8385                        })
 8386                        .log_err();
 8387                })
 8388        })
 8389    }
 8390
 8391    fn render_breakpoint(
 8392        &self,
 8393        position: Anchor,
 8394        row: DisplayRow,
 8395        breakpoint: &Breakpoint,
 8396        state: Option<BreakpointSessionState>,
 8397        cx: &mut Context<Self>,
 8398    ) -> IconButton {
 8399        let is_rejected = state.is_some_and(|s| !s.verified);
 8400        // Is it a breakpoint that shows up when hovering over gutter?
 8401        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8402            (false, false),
 8403            |PhantomBreakpointIndicator {
 8404                 is_active,
 8405                 display_row,
 8406                 collides_with_existing_breakpoint,
 8407             }| {
 8408                (
 8409                    is_active && display_row == row,
 8410                    collides_with_existing_breakpoint,
 8411                )
 8412            },
 8413        );
 8414
 8415        let (color, icon) = {
 8416            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8417                (false, false) => ui::IconName::DebugBreakpoint,
 8418                (true, false) => ui::IconName::DebugLogBreakpoint,
 8419                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8420                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8421            };
 8422
 8423            let color = if is_phantom {
 8424                Color::Hint
 8425            } else if is_rejected {
 8426                Color::Disabled
 8427            } else {
 8428                Color::Debugger
 8429            };
 8430
 8431            (color, icon)
 8432        };
 8433
 8434        let breakpoint = Arc::from(breakpoint.clone());
 8435
 8436        let alt_as_text = gpui::Keystroke {
 8437            modifiers: Modifiers::secondary_key(),
 8438            ..Default::default()
 8439        };
 8440        let primary_action_text = if breakpoint.is_disabled() {
 8441            "Enable breakpoint"
 8442        } else if is_phantom && !collides_with_existing {
 8443            "Set breakpoint"
 8444        } else {
 8445            "Unset breakpoint"
 8446        };
 8447        let focus_handle = self.focus_handle.clone();
 8448
 8449        let meta = if is_rejected {
 8450            SharedString::from("No executable code is associated with this line.")
 8451        } else if collides_with_existing && !breakpoint.is_disabled() {
 8452            SharedString::from(format!(
 8453                "{alt_as_text}-click to disable,\nright-click for more options."
 8454            ))
 8455        } else {
 8456            SharedString::from("Right-click for more options.")
 8457        };
 8458        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8459            .icon_size(IconSize::XSmall)
 8460            .size(ui::ButtonSize::None)
 8461            .when(is_rejected, |this| {
 8462                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8463            })
 8464            .icon_color(color)
 8465            .style(ButtonStyle::Transparent)
 8466            .on_click(cx.listener({
 8467                move |editor, event: &ClickEvent, window, cx| {
 8468                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8469                        BreakpointEditAction::InvertState
 8470                    } else {
 8471                        BreakpointEditAction::Toggle
 8472                    };
 8473
 8474                    window.focus(&editor.focus_handle(cx));
 8475                    editor.edit_breakpoint_at_anchor(
 8476                        position,
 8477                        breakpoint.as_ref().clone(),
 8478                        edit_action,
 8479                        cx,
 8480                    );
 8481                }
 8482            }))
 8483            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8484                editor.set_breakpoint_context_menu(
 8485                    row,
 8486                    Some(position),
 8487                    event.position(),
 8488                    window,
 8489                    cx,
 8490                );
 8491            }))
 8492            .tooltip(move |window, cx| {
 8493                Tooltip::with_meta_in(
 8494                    primary_action_text,
 8495                    Some(&ToggleBreakpoint),
 8496                    meta.clone(),
 8497                    &focus_handle,
 8498                    window,
 8499                    cx,
 8500                )
 8501            })
 8502    }
 8503
 8504    fn build_tasks_context(
 8505        project: &Entity<Project>,
 8506        buffer: &Entity<Buffer>,
 8507        buffer_row: u32,
 8508        tasks: &Arc<RunnableTasks>,
 8509        cx: &mut Context<Self>,
 8510    ) -> Task<Option<task::TaskContext>> {
 8511        let position = Point::new(buffer_row, tasks.column);
 8512        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8513        let location = Location {
 8514            buffer: buffer.clone(),
 8515            range: range_start..range_start,
 8516        };
 8517        // Fill in the environmental variables from the tree-sitter captures
 8518        let mut captured_task_variables = TaskVariables::default();
 8519        for (capture_name, value) in tasks.extra_variables.clone() {
 8520            captured_task_variables.insert(
 8521                task::VariableName::Custom(capture_name.into()),
 8522                value.clone(),
 8523            );
 8524        }
 8525        project.update(cx, |project, cx| {
 8526            project.task_store().update(cx, |task_store, cx| {
 8527                task_store.task_context_for_location(captured_task_variables, location, cx)
 8528            })
 8529        })
 8530    }
 8531
 8532    pub fn spawn_nearest_task(
 8533        &mut self,
 8534        action: &SpawnNearestTask,
 8535        window: &mut Window,
 8536        cx: &mut Context<Self>,
 8537    ) {
 8538        let Some((workspace, _)) = self.workspace.clone() else {
 8539            return;
 8540        };
 8541        let Some(project) = self.project.clone() else {
 8542            return;
 8543        };
 8544
 8545        // Try to find a closest, enclosing node using tree-sitter that has a task
 8546        let Some((buffer, buffer_row, tasks)) = self
 8547            .find_enclosing_node_task(cx)
 8548            // Or find the task that's closest in row-distance.
 8549            .or_else(|| self.find_closest_task(cx))
 8550        else {
 8551            return;
 8552        };
 8553
 8554        let reveal_strategy = action.reveal;
 8555        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8556        cx.spawn_in(window, async move |_, cx| {
 8557            let context = task_context.await?;
 8558            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8559
 8560            let resolved = &mut resolved_task.resolved;
 8561            resolved.reveal = reveal_strategy;
 8562
 8563            workspace
 8564                .update_in(cx, |workspace, window, cx| {
 8565                    workspace.schedule_resolved_task(
 8566                        task_source_kind,
 8567                        resolved_task,
 8568                        false,
 8569                        window,
 8570                        cx,
 8571                    );
 8572                })
 8573                .ok()
 8574        })
 8575        .detach();
 8576    }
 8577
 8578    fn find_closest_task(
 8579        &mut self,
 8580        cx: &mut Context<Self>,
 8581    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8582        let cursor_row = self
 8583            .selections
 8584            .newest_adjusted(&self.display_snapshot(cx))
 8585            .head()
 8586            .row;
 8587
 8588        let ((buffer_id, row), tasks) = self
 8589            .tasks
 8590            .iter()
 8591            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8592
 8593        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8594        let tasks = Arc::new(tasks.to_owned());
 8595        Some((buffer, *row, tasks))
 8596    }
 8597
 8598    fn find_enclosing_node_task(
 8599        &mut self,
 8600        cx: &mut Context<Self>,
 8601    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8602        let snapshot = self.buffer.read(cx).snapshot(cx);
 8603        let offset = self
 8604            .selections
 8605            .newest::<usize>(&self.display_snapshot(cx))
 8606            .head();
 8607        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8608        let buffer_id = excerpt.buffer().remote_id();
 8609
 8610        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8611        let mut cursor = layer.node().walk();
 8612
 8613        while cursor.goto_first_child_for_byte(offset).is_some() {
 8614            if cursor.node().end_byte() == offset {
 8615                cursor.goto_next_sibling();
 8616            }
 8617        }
 8618
 8619        // Ascend to the smallest ancestor that contains the range and has a task.
 8620        loop {
 8621            let node = cursor.node();
 8622            let node_range = node.byte_range();
 8623            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8624
 8625            // Check if this node contains our offset
 8626            if node_range.start <= offset && node_range.end >= offset {
 8627                // If it contains offset, check for task
 8628                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8629                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8630                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8631                }
 8632            }
 8633
 8634            if !cursor.goto_parent() {
 8635                break;
 8636            }
 8637        }
 8638        None
 8639    }
 8640
 8641    fn render_run_indicator(
 8642        &self,
 8643        _style: &EditorStyle,
 8644        is_active: bool,
 8645        row: DisplayRow,
 8646        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8647        cx: &mut Context<Self>,
 8648    ) -> IconButton {
 8649        let color = Color::Muted;
 8650        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8651
 8652        IconButton::new(
 8653            ("run_indicator", row.0 as usize),
 8654            ui::IconName::PlayOutlined,
 8655        )
 8656        .shape(ui::IconButtonShape::Square)
 8657        .icon_size(IconSize::XSmall)
 8658        .icon_color(color)
 8659        .toggle_state(is_active)
 8660        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8661            let quick_launch = match e {
 8662                ClickEvent::Keyboard(_) => true,
 8663                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8664            };
 8665
 8666            window.focus(&editor.focus_handle(cx));
 8667            editor.toggle_code_actions(
 8668                &ToggleCodeActions {
 8669                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8670                    quick_launch,
 8671                },
 8672                window,
 8673                cx,
 8674            );
 8675        }))
 8676        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8677            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8678        }))
 8679    }
 8680
 8681    pub fn context_menu_visible(&self) -> bool {
 8682        !self.edit_prediction_preview_is_active()
 8683            && self
 8684                .context_menu
 8685                .borrow()
 8686                .as_ref()
 8687                .is_some_and(|menu| menu.visible())
 8688    }
 8689
 8690    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8691        self.context_menu
 8692            .borrow()
 8693            .as_ref()
 8694            .map(|menu| menu.origin())
 8695    }
 8696
 8697    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8698        self.context_menu_options = Some(options);
 8699    }
 8700
 8701    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8702    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8703
 8704    fn render_edit_prediction_popover(
 8705        &mut self,
 8706        text_bounds: &Bounds<Pixels>,
 8707        content_origin: gpui::Point<Pixels>,
 8708        right_margin: Pixels,
 8709        editor_snapshot: &EditorSnapshot,
 8710        visible_row_range: Range<DisplayRow>,
 8711        scroll_top: ScrollOffset,
 8712        scroll_bottom: ScrollOffset,
 8713        line_layouts: &[LineWithInvisibles],
 8714        line_height: Pixels,
 8715        scroll_position: gpui::Point<ScrollOffset>,
 8716        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8717        newest_selection_head: Option<DisplayPoint>,
 8718        editor_width: Pixels,
 8719        style: &EditorStyle,
 8720        window: &mut Window,
 8721        cx: &mut App,
 8722    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8723        if self.mode().is_minimap() {
 8724            return None;
 8725        }
 8726        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8727
 8728        if self.edit_prediction_visible_in_cursor_popover(true) {
 8729            return None;
 8730        }
 8731
 8732        match &active_edit_prediction.completion {
 8733            EditPrediction::MoveWithin { target, .. } => {
 8734                let target_display_point = target.to_display_point(editor_snapshot);
 8735
 8736                if self.edit_prediction_requires_modifier() {
 8737                    if !self.edit_prediction_preview_is_active() {
 8738                        return None;
 8739                    }
 8740
 8741                    self.render_edit_prediction_modifier_jump_popover(
 8742                        text_bounds,
 8743                        content_origin,
 8744                        visible_row_range,
 8745                        line_layouts,
 8746                        line_height,
 8747                        scroll_pixel_position,
 8748                        newest_selection_head,
 8749                        target_display_point,
 8750                        window,
 8751                        cx,
 8752                    )
 8753                } else {
 8754                    self.render_edit_prediction_eager_jump_popover(
 8755                        text_bounds,
 8756                        content_origin,
 8757                        editor_snapshot,
 8758                        visible_row_range,
 8759                        scroll_top,
 8760                        scroll_bottom,
 8761                        line_height,
 8762                        scroll_pixel_position,
 8763                        target_display_point,
 8764                        editor_width,
 8765                        window,
 8766                        cx,
 8767                    )
 8768                }
 8769            }
 8770            EditPrediction::Edit {
 8771                display_mode: EditDisplayMode::Inline,
 8772                ..
 8773            } => None,
 8774            EditPrediction::Edit {
 8775                display_mode: EditDisplayMode::TabAccept,
 8776                edits,
 8777                ..
 8778            } => {
 8779                let range = &edits.first()?.0;
 8780                let target_display_point = range.end.to_display_point(editor_snapshot);
 8781
 8782                self.render_edit_prediction_end_of_line_popover(
 8783                    "Accept",
 8784                    editor_snapshot,
 8785                    visible_row_range,
 8786                    target_display_point,
 8787                    line_height,
 8788                    scroll_pixel_position,
 8789                    content_origin,
 8790                    editor_width,
 8791                    window,
 8792                    cx,
 8793                )
 8794            }
 8795            EditPrediction::Edit {
 8796                edits,
 8797                edit_preview,
 8798                display_mode: EditDisplayMode::DiffPopover,
 8799                snapshot,
 8800            } => self.render_edit_prediction_diff_popover(
 8801                text_bounds,
 8802                content_origin,
 8803                right_margin,
 8804                editor_snapshot,
 8805                visible_row_range,
 8806                line_layouts,
 8807                line_height,
 8808                scroll_position,
 8809                scroll_pixel_position,
 8810                newest_selection_head,
 8811                editor_width,
 8812                style,
 8813                edits,
 8814                edit_preview,
 8815                snapshot,
 8816                window,
 8817                cx,
 8818            ),
 8819            EditPrediction::MoveOutside { snapshot, .. } => {
 8820                let file_name = snapshot
 8821                    .file()
 8822                    .map(|file| file.file_name(cx))
 8823                    .unwrap_or("untitled");
 8824                let mut element = self
 8825                    .render_edit_prediction_line_popover(
 8826                        format!("Jump to {file_name}"),
 8827                        Some(IconName::ZedPredict),
 8828                        window,
 8829                        cx,
 8830                    )
 8831                    .into_any();
 8832
 8833                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8834                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8835                let origin_y = text_bounds.size.height - size.height - px(30.);
 8836                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8837                element.prepaint_at(origin, window, cx);
 8838
 8839                Some((element, origin))
 8840            }
 8841        }
 8842    }
 8843
 8844    fn render_edit_prediction_modifier_jump_popover(
 8845        &mut self,
 8846        text_bounds: &Bounds<Pixels>,
 8847        content_origin: gpui::Point<Pixels>,
 8848        visible_row_range: Range<DisplayRow>,
 8849        line_layouts: &[LineWithInvisibles],
 8850        line_height: Pixels,
 8851        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8852        newest_selection_head: Option<DisplayPoint>,
 8853        target_display_point: DisplayPoint,
 8854        window: &mut Window,
 8855        cx: &mut App,
 8856    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8857        let scrolled_content_origin =
 8858            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8859
 8860        const SCROLL_PADDING_Y: Pixels = px(12.);
 8861
 8862        if target_display_point.row() < visible_row_range.start {
 8863            return self.render_edit_prediction_scroll_popover(
 8864                |_| SCROLL_PADDING_Y,
 8865                IconName::ArrowUp,
 8866                visible_row_range,
 8867                line_layouts,
 8868                newest_selection_head,
 8869                scrolled_content_origin,
 8870                window,
 8871                cx,
 8872            );
 8873        } else if target_display_point.row() >= visible_row_range.end {
 8874            return self.render_edit_prediction_scroll_popover(
 8875                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8876                IconName::ArrowDown,
 8877                visible_row_range,
 8878                line_layouts,
 8879                newest_selection_head,
 8880                scrolled_content_origin,
 8881                window,
 8882                cx,
 8883            );
 8884        }
 8885
 8886        const POLE_WIDTH: Pixels = px(2.);
 8887
 8888        let line_layout =
 8889            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8890        let target_column = target_display_point.column() as usize;
 8891
 8892        let target_x = line_layout.x_for_index(target_column);
 8893        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8894            - scroll_pixel_position.y;
 8895
 8896        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8897
 8898        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8899        border_color.l += 0.001;
 8900
 8901        let mut element = v_flex()
 8902            .items_end()
 8903            .when(flag_on_right, |el| el.items_start())
 8904            .child(if flag_on_right {
 8905                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8906                    .rounded_bl(px(0.))
 8907                    .rounded_tl(px(0.))
 8908                    .border_l_2()
 8909                    .border_color(border_color)
 8910            } else {
 8911                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8912                    .rounded_br(px(0.))
 8913                    .rounded_tr(px(0.))
 8914                    .border_r_2()
 8915                    .border_color(border_color)
 8916            })
 8917            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8918            .into_any();
 8919
 8920        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8921
 8922        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8923            - point(
 8924                if flag_on_right {
 8925                    POLE_WIDTH
 8926                } else {
 8927                    size.width - POLE_WIDTH
 8928                },
 8929                size.height - line_height,
 8930            );
 8931
 8932        origin.x = origin.x.max(content_origin.x);
 8933
 8934        element.prepaint_at(origin, window, cx);
 8935
 8936        Some((element, origin))
 8937    }
 8938
 8939    fn render_edit_prediction_scroll_popover(
 8940        &mut self,
 8941        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8942        scroll_icon: IconName,
 8943        visible_row_range: Range<DisplayRow>,
 8944        line_layouts: &[LineWithInvisibles],
 8945        newest_selection_head: Option<DisplayPoint>,
 8946        scrolled_content_origin: gpui::Point<Pixels>,
 8947        window: &mut Window,
 8948        cx: &mut App,
 8949    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8950        let mut element = self
 8951            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8952            .into_any();
 8953
 8954        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8955
 8956        let cursor = newest_selection_head?;
 8957        let cursor_row_layout =
 8958            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8959        let cursor_column = cursor.column() as usize;
 8960
 8961        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8962
 8963        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8964
 8965        element.prepaint_at(origin, window, cx);
 8966        Some((element, origin))
 8967    }
 8968
 8969    fn render_edit_prediction_eager_jump_popover(
 8970        &mut self,
 8971        text_bounds: &Bounds<Pixels>,
 8972        content_origin: gpui::Point<Pixels>,
 8973        editor_snapshot: &EditorSnapshot,
 8974        visible_row_range: Range<DisplayRow>,
 8975        scroll_top: ScrollOffset,
 8976        scroll_bottom: ScrollOffset,
 8977        line_height: Pixels,
 8978        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8979        target_display_point: DisplayPoint,
 8980        editor_width: Pixels,
 8981        window: &mut Window,
 8982        cx: &mut App,
 8983    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8984        if target_display_point.row().as_f64() < scroll_top {
 8985            let mut element = self
 8986                .render_edit_prediction_line_popover(
 8987                    "Jump to Edit",
 8988                    Some(IconName::ArrowUp),
 8989                    window,
 8990                    cx,
 8991                )
 8992                .into_any();
 8993
 8994            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8995            let offset = point(
 8996                (text_bounds.size.width - size.width) / 2.,
 8997                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8998            );
 8999
 9000            let origin = text_bounds.origin + offset;
 9001            element.prepaint_at(origin, window, cx);
 9002            Some((element, origin))
 9003        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9004            let mut element = self
 9005                .render_edit_prediction_line_popover(
 9006                    "Jump to Edit",
 9007                    Some(IconName::ArrowDown),
 9008                    window,
 9009                    cx,
 9010                )
 9011                .into_any();
 9012
 9013            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9014            let offset = point(
 9015                (text_bounds.size.width - size.width) / 2.,
 9016                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9017            );
 9018
 9019            let origin = text_bounds.origin + offset;
 9020            element.prepaint_at(origin, window, cx);
 9021            Some((element, origin))
 9022        } else {
 9023            self.render_edit_prediction_end_of_line_popover(
 9024                "Jump to Edit",
 9025                editor_snapshot,
 9026                visible_row_range,
 9027                target_display_point,
 9028                line_height,
 9029                scroll_pixel_position,
 9030                content_origin,
 9031                editor_width,
 9032                window,
 9033                cx,
 9034            )
 9035        }
 9036    }
 9037
 9038    fn render_edit_prediction_end_of_line_popover(
 9039        self: &mut Editor,
 9040        label: &'static str,
 9041        editor_snapshot: &EditorSnapshot,
 9042        visible_row_range: Range<DisplayRow>,
 9043        target_display_point: DisplayPoint,
 9044        line_height: Pixels,
 9045        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9046        content_origin: gpui::Point<Pixels>,
 9047        editor_width: Pixels,
 9048        window: &mut Window,
 9049        cx: &mut App,
 9050    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9051        let target_line_end = DisplayPoint::new(
 9052            target_display_point.row(),
 9053            editor_snapshot.line_len(target_display_point.row()),
 9054        );
 9055
 9056        let mut element = self
 9057            .render_edit_prediction_line_popover(label, None, window, cx)
 9058            .into_any();
 9059
 9060        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9061
 9062        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9063
 9064        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9065        let mut origin = start_point
 9066            + line_origin
 9067            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9068        origin.x = origin.x.max(content_origin.x);
 9069
 9070        let max_x = content_origin.x + editor_width - size.width;
 9071
 9072        if origin.x > max_x {
 9073            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9074
 9075            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9076                origin.y += offset;
 9077                IconName::ArrowUp
 9078            } else {
 9079                origin.y -= offset;
 9080                IconName::ArrowDown
 9081            };
 9082
 9083            element = self
 9084                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9085                .into_any();
 9086
 9087            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9088
 9089            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9090        }
 9091
 9092        element.prepaint_at(origin, window, cx);
 9093        Some((element, origin))
 9094    }
 9095
 9096    fn render_edit_prediction_diff_popover(
 9097        self: &Editor,
 9098        text_bounds: &Bounds<Pixels>,
 9099        content_origin: gpui::Point<Pixels>,
 9100        right_margin: Pixels,
 9101        editor_snapshot: &EditorSnapshot,
 9102        visible_row_range: Range<DisplayRow>,
 9103        line_layouts: &[LineWithInvisibles],
 9104        line_height: Pixels,
 9105        scroll_position: gpui::Point<ScrollOffset>,
 9106        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9107        newest_selection_head: Option<DisplayPoint>,
 9108        editor_width: Pixels,
 9109        style: &EditorStyle,
 9110        edits: &Vec<(Range<Anchor>, String)>,
 9111        edit_preview: &Option<language::EditPreview>,
 9112        snapshot: &language::BufferSnapshot,
 9113        window: &mut Window,
 9114        cx: &mut App,
 9115    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9116        let edit_start = edits
 9117            .first()
 9118            .unwrap()
 9119            .0
 9120            .start
 9121            .to_display_point(editor_snapshot);
 9122        let edit_end = edits
 9123            .last()
 9124            .unwrap()
 9125            .0
 9126            .end
 9127            .to_display_point(editor_snapshot);
 9128
 9129        let is_visible = visible_row_range.contains(&edit_start.row())
 9130            || visible_row_range.contains(&edit_end.row());
 9131        if !is_visible {
 9132            return None;
 9133        }
 9134
 9135        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9136            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9137        } else {
 9138            // Fallback for providers without edit_preview
 9139            crate::edit_prediction_fallback_text(edits, cx)
 9140        };
 9141
 9142        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9143        let line_count = highlighted_edits.text.lines().count();
 9144
 9145        const BORDER_WIDTH: Pixels = px(1.);
 9146
 9147        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9148        let has_keybind = keybind.is_some();
 9149
 9150        let mut element = h_flex()
 9151            .items_start()
 9152            .child(
 9153                h_flex()
 9154                    .bg(cx.theme().colors().editor_background)
 9155                    .border(BORDER_WIDTH)
 9156                    .shadow_xs()
 9157                    .border_color(cx.theme().colors().border)
 9158                    .rounded_l_lg()
 9159                    .when(line_count > 1, |el| el.rounded_br_lg())
 9160                    .pr_1()
 9161                    .child(styled_text),
 9162            )
 9163            .child(
 9164                h_flex()
 9165                    .h(line_height + BORDER_WIDTH * 2.)
 9166                    .px_1p5()
 9167                    .gap_1()
 9168                    // Workaround: For some reason, there's a gap if we don't do this
 9169                    .ml(-BORDER_WIDTH)
 9170                    .shadow(vec![gpui::BoxShadow {
 9171                        color: gpui::black().opacity(0.05),
 9172                        offset: point(px(1.), px(1.)),
 9173                        blur_radius: px(2.),
 9174                        spread_radius: px(0.),
 9175                    }])
 9176                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9177                    .border(BORDER_WIDTH)
 9178                    .border_color(cx.theme().colors().border)
 9179                    .rounded_r_lg()
 9180                    .id("edit_prediction_diff_popover_keybind")
 9181                    .when(!has_keybind, |el| {
 9182                        let status_colors = cx.theme().status();
 9183
 9184                        el.bg(status_colors.error_background)
 9185                            .border_color(status_colors.error.opacity(0.6))
 9186                            .child(Icon::new(IconName::Info).color(Color::Error))
 9187                            .cursor_default()
 9188                            .hoverable_tooltip(move |_window, cx| {
 9189                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9190                            })
 9191                    })
 9192                    .children(keybind),
 9193            )
 9194            .into_any();
 9195
 9196        let longest_row =
 9197            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9198        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9199            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9200        } else {
 9201            layout_line(
 9202                longest_row,
 9203                editor_snapshot,
 9204                style,
 9205                editor_width,
 9206                |_| false,
 9207                window,
 9208                cx,
 9209            )
 9210            .width
 9211        };
 9212
 9213        let viewport_bounds =
 9214            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9215                right: -right_margin,
 9216                ..Default::default()
 9217            });
 9218
 9219        let x_after_longest = Pixels::from(
 9220            ScrollPixelOffset::from(
 9221                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9222            ) - scroll_pixel_position.x,
 9223        );
 9224
 9225        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9226
 9227        // Fully visible if it can be displayed within the window (allow overlapping other
 9228        // panes). However, this is only allowed if the popover starts within text_bounds.
 9229        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9230            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9231
 9232        let mut origin = if can_position_to_the_right {
 9233            point(
 9234                x_after_longest,
 9235                text_bounds.origin.y
 9236                    + Pixels::from(
 9237                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9238                            - scroll_pixel_position.y,
 9239                    ),
 9240            )
 9241        } else {
 9242            let cursor_row = newest_selection_head.map(|head| head.row());
 9243            let above_edit = edit_start
 9244                .row()
 9245                .0
 9246                .checked_sub(line_count as u32)
 9247                .map(DisplayRow);
 9248            let below_edit = Some(edit_end.row() + 1);
 9249            let above_cursor =
 9250                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9251            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9252
 9253            // Place the edit popover adjacent to the edit if there is a location
 9254            // available that is onscreen and does not obscure the cursor. Otherwise,
 9255            // place it adjacent to the cursor.
 9256            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9257                .into_iter()
 9258                .flatten()
 9259                .find(|&start_row| {
 9260                    let end_row = start_row + line_count as u32;
 9261                    visible_row_range.contains(&start_row)
 9262                        && visible_row_range.contains(&end_row)
 9263                        && cursor_row
 9264                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9265                })?;
 9266
 9267            content_origin
 9268                + point(
 9269                    Pixels::from(-scroll_pixel_position.x),
 9270                    Pixels::from(
 9271                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9272                    ),
 9273                )
 9274        };
 9275
 9276        origin.x -= BORDER_WIDTH;
 9277
 9278        window.defer_draw(element, origin, 1);
 9279
 9280        // Do not return an element, since it will already be drawn due to defer_draw.
 9281        None
 9282    }
 9283
 9284    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9285        px(30.)
 9286    }
 9287
 9288    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9289        if self.read_only(cx) {
 9290            cx.theme().players().read_only()
 9291        } else {
 9292            self.style.as_ref().unwrap().local_player
 9293        }
 9294    }
 9295
 9296    fn render_edit_prediction_accept_keybind(
 9297        &self,
 9298        window: &mut Window,
 9299        cx: &mut App,
 9300    ) -> Option<AnyElement> {
 9301        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9302        let accept_keystroke = accept_binding.keystroke()?;
 9303
 9304        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9305
 9306        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9307            Color::Accent
 9308        } else {
 9309            Color::Muted
 9310        };
 9311
 9312        h_flex()
 9313            .px_0p5()
 9314            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9315            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9316            .text_size(TextSize::XSmall.rems(cx))
 9317            .child(h_flex().children(ui::render_modifiers(
 9318                accept_keystroke.modifiers(),
 9319                PlatformStyle::platform(),
 9320                Some(modifiers_color),
 9321                Some(IconSize::XSmall.rems().into()),
 9322                true,
 9323            )))
 9324            .when(is_platform_style_mac, |parent| {
 9325                parent.child(accept_keystroke.key().to_string())
 9326            })
 9327            .when(!is_platform_style_mac, |parent| {
 9328                parent.child(
 9329                    Key::new(
 9330                        util::capitalize(accept_keystroke.key()),
 9331                        Some(Color::Default),
 9332                    )
 9333                    .size(Some(IconSize::XSmall.rems().into())),
 9334                )
 9335            })
 9336            .into_any()
 9337            .into()
 9338    }
 9339
 9340    fn render_edit_prediction_line_popover(
 9341        &self,
 9342        label: impl Into<SharedString>,
 9343        icon: Option<IconName>,
 9344        window: &mut Window,
 9345        cx: &mut App,
 9346    ) -> Stateful<Div> {
 9347        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9348
 9349        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9350        let has_keybind = keybind.is_some();
 9351
 9352        h_flex()
 9353            .id("ep-line-popover")
 9354            .py_0p5()
 9355            .pl_1()
 9356            .pr(padding_right)
 9357            .gap_1()
 9358            .rounded_md()
 9359            .border_1()
 9360            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9361            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9362            .shadow_xs()
 9363            .when(!has_keybind, |el| {
 9364                let status_colors = cx.theme().status();
 9365
 9366                el.bg(status_colors.error_background)
 9367                    .border_color(status_colors.error.opacity(0.6))
 9368                    .pl_2()
 9369                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9370                    .cursor_default()
 9371                    .hoverable_tooltip(move |_window, cx| {
 9372                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9373                    })
 9374            })
 9375            .children(keybind)
 9376            .child(
 9377                Label::new(label)
 9378                    .size(LabelSize::Small)
 9379                    .when(!has_keybind, |el| {
 9380                        el.color(cx.theme().status().error.into()).strikethrough()
 9381                    }),
 9382            )
 9383            .when(!has_keybind, |el| {
 9384                el.child(
 9385                    h_flex().ml_1().child(
 9386                        Icon::new(IconName::Info)
 9387                            .size(IconSize::Small)
 9388                            .color(cx.theme().status().error.into()),
 9389                    ),
 9390                )
 9391            })
 9392            .when_some(icon, |element, icon| {
 9393                element.child(
 9394                    div()
 9395                        .mt(px(1.5))
 9396                        .child(Icon::new(icon).size(IconSize::Small)),
 9397                )
 9398            })
 9399    }
 9400
 9401    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9402        let accent_color = cx.theme().colors().text_accent;
 9403        let editor_bg_color = cx.theme().colors().editor_background;
 9404        editor_bg_color.blend(accent_color.opacity(0.1))
 9405    }
 9406
 9407    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9408        let accent_color = cx.theme().colors().text_accent;
 9409        let editor_bg_color = cx.theme().colors().editor_background;
 9410        editor_bg_color.blend(accent_color.opacity(0.6))
 9411    }
 9412    fn get_prediction_provider_icon_name(
 9413        provider: &Option<RegisteredEditPredictionProvider>,
 9414    ) -> IconName {
 9415        match provider {
 9416            Some(provider) => match provider.provider.name() {
 9417                "copilot" => IconName::Copilot,
 9418                "supermaven" => IconName::Supermaven,
 9419                _ => IconName::ZedPredict,
 9420            },
 9421            None => IconName::ZedPredict,
 9422        }
 9423    }
 9424
 9425    fn render_edit_prediction_cursor_popover(
 9426        &self,
 9427        min_width: Pixels,
 9428        max_width: Pixels,
 9429        cursor_point: Point,
 9430        style: &EditorStyle,
 9431        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9432        _window: &Window,
 9433        cx: &mut Context<Editor>,
 9434    ) -> Option<AnyElement> {
 9435        let provider = self.edit_prediction_provider.as_ref()?;
 9436        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9437
 9438        let is_refreshing = provider.provider.is_refreshing(cx);
 9439
 9440        fn pending_completion_container(icon: IconName) -> Div {
 9441            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9442        }
 9443
 9444        let completion = match &self.active_edit_prediction {
 9445            Some(prediction) => {
 9446                if !self.has_visible_completions_menu() {
 9447                    const RADIUS: Pixels = px(6.);
 9448                    const BORDER_WIDTH: Pixels = px(1.);
 9449
 9450                    return Some(
 9451                        h_flex()
 9452                            .elevation_2(cx)
 9453                            .border(BORDER_WIDTH)
 9454                            .border_color(cx.theme().colors().border)
 9455                            .when(accept_keystroke.is_none(), |el| {
 9456                                el.border_color(cx.theme().status().error)
 9457                            })
 9458                            .rounded(RADIUS)
 9459                            .rounded_tl(px(0.))
 9460                            .overflow_hidden()
 9461                            .child(div().px_1p5().child(match &prediction.completion {
 9462                                EditPrediction::MoveWithin { target, snapshot } => {
 9463                                    use text::ToPoint as _;
 9464                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9465                                    {
 9466                                        Icon::new(IconName::ZedPredictDown)
 9467                                    } else {
 9468                                        Icon::new(IconName::ZedPredictUp)
 9469                                    }
 9470                                }
 9471                                EditPrediction::MoveOutside { .. } => {
 9472                                    // TODO [zeta2] custom icon for external jump?
 9473                                    Icon::new(provider_icon)
 9474                                }
 9475                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9476                            }))
 9477                            .child(
 9478                                h_flex()
 9479                                    .gap_1()
 9480                                    .py_1()
 9481                                    .px_2()
 9482                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9483                                    .border_l_1()
 9484                                    .border_color(cx.theme().colors().border)
 9485                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9486                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9487                                        el.child(
 9488                                            Label::new("Hold")
 9489                                                .size(LabelSize::Small)
 9490                                                .when(accept_keystroke.is_none(), |el| {
 9491                                                    el.strikethrough()
 9492                                                })
 9493                                                .line_height_style(LineHeightStyle::UiLabel),
 9494                                        )
 9495                                    })
 9496                                    .id("edit_prediction_cursor_popover_keybind")
 9497                                    .when(accept_keystroke.is_none(), |el| {
 9498                                        let status_colors = cx.theme().status();
 9499
 9500                                        el.bg(status_colors.error_background)
 9501                                            .border_color(status_colors.error.opacity(0.6))
 9502                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9503                                            .cursor_default()
 9504                                            .hoverable_tooltip(move |_window, cx| {
 9505                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9506                                                    .into()
 9507                                            })
 9508                                    })
 9509                                    .when_some(
 9510                                        accept_keystroke.as_ref(),
 9511                                        |el, accept_keystroke| {
 9512                                            el.child(h_flex().children(ui::render_modifiers(
 9513                                                accept_keystroke.modifiers(),
 9514                                                PlatformStyle::platform(),
 9515                                                Some(Color::Default),
 9516                                                Some(IconSize::XSmall.rems().into()),
 9517                                                false,
 9518                                            )))
 9519                                        },
 9520                                    ),
 9521                            )
 9522                            .into_any(),
 9523                    );
 9524                }
 9525
 9526                self.render_edit_prediction_cursor_popover_preview(
 9527                    prediction,
 9528                    cursor_point,
 9529                    style,
 9530                    cx,
 9531                )?
 9532            }
 9533
 9534            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9535                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9536                    stale_completion,
 9537                    cursor_point,
 9538                    style,
 9539                    cx,
 9540                )?,
 9541
 9542                None => pending_completion_container(provider_icon)
 9543                    .child(Label::new("...").size(LabelSize::Small)),
 9544            },
 9545
 9546            None => pending_completion_container(provider_icon)
 9547                .child(Label::new("...").size(LabelSize::Small)),
 9548        };
 9549
 9550        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9551            completion
 9552                .with_animation(
 9553                    "loading-completion",
 9554                    Animation::new(Duration::from_secs(2))
 9555                        .repeat()
 9556                        .with_easing(pulsating_between(0.4, 0.8)),
 9557                    |label, delta| label.opacity(delta),
 9558                )
 9559                .into_any_element()
 9560        } else {
 9561            completion.into_any_element()
 9562        };
 9563
 9564        let has_completion = self.active_edit_prediction.is_some();
 9565
 9566        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9567        Some(
 9568            h_flex()
 9569                .min_w(min_width)
 9570                .max_w(max_width)
 9571                .flex_1()
 9572                .elevation_2(cx)
 9573                .border_color(cx.theme().colors().border)
 9574                .child(
 9575                    div()
 9576                        .flex_1()
 9577                        .py_1()
 9578                        .px_2()
 9579                        .overflow_hidden()
 9580                        .child(completion),
 9581                )
 9582                .when_some(accept_keystroke, |el, accept_keystroke| {
 9583                    if !accept_keystroke.modifiers().modified() {
 9584                        return el;
 9585                    }
 9586
 9587                    el.child(
 9588                        h_flex()
 9589                            .h_full()
 9590                            .border_l_1()
 9591                            .rounded_r_lg()
 9592                            .border_color(cx.theme().colors().border)
 9593                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9594                            .gap_1()
 9595                            .py_1()
 9596                            .px_2()
 9597                            .child(
 9598                                h_flex()
 9599                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9600                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9601                                    .child(h_flex().children(ui::render_modifiers(
 9602                                        accept_keystroke.modifiers(),
 9603                                        PlatformStyle::platform(),
 9604                                        Some(if !has_completion {
 9605                                            Color::Muted
 9606                                        } else {
 9607                                            Color::Default
 9608                                        }),
 9609                                        None,
 9610                                        false,
 9611                                    ))),
 9612                            )
 9613                            .child(Label::new("Preview").into_any_element())
 9614                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9615                    )
 9616                })
 9617                .into_any(),
 9618        )
 9619    }
 9620
 9621    fn render_edit_prediction_cursor_popover_preview(
 9622        &self,
 9623        completion: &EditPredictionState,
 9624        cursor_point: Point,
 9625        style: &EditorStyle,
 9626        cx: &mut Context<Editor>,
 9627    ) -> Option<Div> {
 9628        use text::ToPoint as _;
 9629
 9630        fn render_relative_row_jump(
 9631            prefix: impl Into<String>,
 9632            current_row: u32,
 9633            target_row: u32,
 9634        ) -> Div {
 9635            let (row_diff, arrow) = if target_row < current_row {
 9636                (current_row - target_row, IconName::ArrowUp)
 9637            } else {
 9638                (target_row - current_row, IconName::ArrowDown)
 9639            };
 9640
 9641            h_flex()
 9642                .child(
 9643                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9644                        .color(Color::Muted)
 9645                        .size(LabelSize::Small),
 9646                )
 9647                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9648        }
 9649
 9650        let supports_jump = self
 9651            .edit_prediction_provider
 9652            .as_ref()
 9653            .map(|provider| provider.provider.supports_jump_to_edit())
 9654            .unwrap_or(true);
 9655
 9656        match &completion.completion {
 9657            EditPrediction::MoveWithin {
 9658                target, snapshot, ..
 9659            } => {
 9660                if !supports_jump {
 9661                    return None;
 9662                }
 9663
 9664                Some(
 9665                    h_flex()
 9666                        .px_2()
 9667                        .gap_2()
 9668                        .flex_1()
 9669                        .child(
 9670                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9671                                Icon::new(IconName::ZedPredictDown)
 9672                            } else {
 9673                                Icon::new(IconName::ZedPredictUp)
 9674                            },
 9675                        )
 9676                        .child(Label::new("Jump to Edit")),
 9677                )
 9678            }
 9679            EditPrediction::MoveOutside { snapshot, .. } => {
 9680                let file_name = snapshot
 9681                    .file()
 9682                    .map(|file| file.file_name(cx))
 9683                    .unwrap_or("untitled");
 9684                Some(
 9685                    h_flex()
 9686                        .px_2()
 9687                        .gap_2()
 9688                        .flex_1()
 9689                        .child(Icon::new(IconName::ZedPredict))
 9690                        .child(Label::new(format!("Jump to {file_name}"))),
 9691                )
 9692            }
 9693            EditPrediction::Edit {
 9694                edits,
 9695                edit_preview,
 9696                snapshot,
 9697                display_mode: _,
 9698            } => {
 9699                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9700
 9701                let (highlighted_edits, has_more_lines) =
 9702                    if let Some(edit_preview) = edit_preview.as_ref() {
 9703                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9704                            .first_line_preview()
 9705                    } else {
 9706                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9707                    };
 9708
 9709                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9710                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9711
 9712                let preview = h_flex()
 9713                    .gap_1()
 9714                    .min_w_16()
 9715                    .child(styled_text)
 9716                    .when(has_more_lines, |parent| parent.child(""));
 9717
 9718                let left = if supports_jump && first_edit_row != cursor_point.row {
 9719                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9720                        .into_any_element()
 9721                } else {
 9722                    let icon_name =
 9723                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9724                    Icon::new(icon_name).into_any_element()
 9725                };
 9726
 9727                Some(
 9728                    h_flex()
 9729                        .h_full()
 9730                        .flex_1()
 9731                        .gap_2()
 9732                        .pr_1()
 9733                        .overflow_x_hidden()
 9734                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9735                        .child(left)
 9736                        .child(preview),
 9737                )
 9738            }
 9739        }
 9740    }
 9741
 9742    pub fn render_context_menu(
 9743        &self,
 9744        style: &EditorStyle,
 9745        max_height_in_lines: u32,
 9746        window: &mut Window,
 9747        cx: &mut Context<Editor>,
 9748    ) -> Option<AnyElement> {
 9749        let menu = self.context_menu.borrow();
 9750        let menu = menu.as_ref()?;
 9751        if !menu.visible() {
 9752            return None;
 9753        };
 9754        Some(menu.render(style, max_height_in_lines, window, cx))
 9755    }
 9756
 9757    fn render_context_menu_aside(
 9758        &mut self,
 9759        max_size: Size<Pixels>,
 9760        window: &mut Window,
 9761        cx: &mut Context<Editor>,
 9762    ) -> Option<AnyElement> {
 9763        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9764            if menu.visible() {
 9765                menu.render_aside(max_size, window, cx)
 9766            } else {
 9767                None
 9768            }
 9769        })
 9770    }
 9771
 9772    fn hide_context_menu(
 9773        &mut self,
 9774        window: &mut Window,
 9775        cx: &mut Context<Self>,
 9776    ) -> Option<CodeContextMenu> {
 9777        cx.notify();
 9778        self.completion_tasks.clear();
 9779        let context_menu = self.context_menu.borrow_mut().take();
 9780        self.stale_edit_prediction_in_menu.take();
 9781        self.update_visible_edit_prediction(window, cx);
 9782        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9783            && let Some(completion_provider) = &self.completion_provider
 9784        {
 9785            completion_provider.selection_changed(None, window, cx);
 9786        }
 9787        context_menu
 9788    }
 9789
 9790    fn show_snippet_choices(
 9791        &mut self,
 9792        choices: &Vec<String>,
 9793        selection: Range<Anchor>,
 9794        cx: &mut Context<Self>,
 9795    ) {
 9796        let Some((_, buffer, _)) = self
 9797            .buffer()
 9798            .read(cx)
 9799            .excerpt_containing(selection.start, cx)
 9800        else {
 9801            return;
 9802        };
 9803        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9804        else {
 9805            return;
 9806        };
 9807        if buffer != end_buffer {
 9808            log::error!("expected anchor range to have matching buffer IDs");
 9809            return;
 9810        }
 9811
 9812        let id = post_inc(&mut self.next_completion_id);
 9813        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9814        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9815            CompletionsMenu::new_snippet_choices(
 9816                id,
 9817                true,
 9818                choices,
 9819                selection,
 9820                buffer,
 9821                snippet_sort_order,
 9822            ),
 9823        ));
 9824    }
 9825
 9826    pub fn insert_snippet(
 9827        &mut self,
 9828        insertion_ranges: &[Range<usize>],
 9829        snippet: Snippet,
 9830        window: &mut Window,
 9831        cx: &mut Context<Self>,
 9832    ) -> Result<()> {
 9833        struct Tabstop<T> {
 9834            is_end_tabstop: bool,
 9835            ranges: Vec<Range<T>>,
 9836            choices: Option<Vec<String>>,
 9837        }
 9838
 9839        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9840            let snippet_text: Arc<str> = snippet.text.clone().into();
 9841            let edits = insertion_ranges
 9842                .iter()
 9843                .cloned()
 9844                .map(|range| (range, snippet_text.clone()));
 9845            let autoindent_mode = AutoindentMode::Block {
 9846                original_indent_columns: Vec::new(),
 9847            };
 9848            buffer.edit(edits, Some(autoindent_mode), cx);
 9849
 9850            let snapshot = &*buffer.read(cx);
 9851            let snippet = &snippet;
 9852            snippet
 9853                .tabstops
 9854                .iter()
 9855                .map(|tabstop| {
 9856                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9857                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9858                    });
 9859                    let mut tabstop_ranges = tabstop
 9860                        .ranges
 9861                        .iter()
 9862                        .flat_map(|tabstop_range| {
 9863                            let mut delta = 0_isize;
 9864                            insertion_ranges.iter().map(move |insertion_range| {
 9865                                let insertion_start = insertion_range.start as isize + delta;
 9866                                delta +=
 9867                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9868
 9869                                let start = ((insertion_start + tabstop_range.start) as usize)
 9870                                    .min(snapshot.len());
 9871                                let end = ((insertion_start + tabstop_range.end) as usize)
 9872                                    .min(snapshot.len());
 9873                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9874                            })
 9875                        })
 9876                        .collect::<Vec<_>>();
 9877                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9878
 9879                    Tabstop {
 9880                        is_end_tabstop,
 9881                        ranges: tabstop_ranges,
 9882                        choices: tabstop.choices.clone(),
 9883                    }
 9884                })
 9885                .collect::<Vec<_>>()
 9886        });
 9887        if let Some(tabstop) = tabstops.first() {
 9888            self.change_selections(Default::default(), window, cx, |s| {
 9889                // Reverse order so that the first range is the newest created selection.
 9890                // Completions will use it and autoscroll will prioritize it.
 9891                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9892            });
 9893
 9894            if let Some(choices) = &tabstop.choices
 9895                && let Some(selection) = tabstop.ranges.first()
 9896            {
 9897                self.show_snippet_choices(choices, selection.clone(), cx)
 9898            }
 9899
 9900            // If we're already at the last tabstop and it's at the end of the snippet,
 9901            // we're done, we don't need to keep the state around.
 9902            if !tabstop.is_end_tabstop {
 9903                let choices = tabstops
 9904                    .iter()
 9905                    .map(|tabstop| tabstop.choices.clone())
 9906                    .collect();
 9907
 9908                let ranges = tabstops
 9909                    .into_iter()
 9910                    .map(|tabstop| tabstop.ranges)
 9911                    .collect::<Vec<_>>();
 9912
 9913                self.snippet_stack.push(SnippetState {
 9914                    active_index: 0,
 9915                    ranges,
 9916                    choices,
 9917                });
 9918            }
 9919
 9920            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9921            if self.autoclose_regions.is_empty() {
 9922                let snapshot = self.buffer.read(cx).snapshot(cx);
 9923                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9924                    let selection_head = selection.head();
 9925                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9926                        continue;
 9927                    };
 9928
 9929                    let mut bracket_pair = None;
 9930                    let max_lookup_length = scope
 9931                        .brackets()
 9932                        .map(|(pair, _)| {
 9933                            pair.start
 9934                                .as_str()
 9935                                .chars()
 9936                                .count()
 9937                                .max(pair.end.as_str().chars().count())
 9938                        })
 9939                        .max();
 9940                    if let Some(max_lookup_length) = max_lookup_length {
 9941                        let next_text = snapshot
 9942                            .chars_at(selection_head)
 9943                            .take(max_lookup_length)
 9944                            .collect::<String>();
 9945                        let prev_text = snapshot
 9946                            .reversed_chars_at(selection_head)
 9947                            .take(max_lookup_length)
 9948                            .collect::<String>();
 9949
 9950                        for (pair, enabled) in scope.brackets() {
 9951                            if enabled
 9952                                && pair.close
 9953                                && prev_text.starts_with(pair.start.as_str())
 9954                                && next_text.starts_with(pair.end.as_str())
 9955                            {
 9956                                bracket_pair = Some(pair.clone());
 9957                                break;
 9958                            }
 9959                        }
 9960                    }
 9961
 9962                    if let Some(pair) = bracket_pair {
 9963                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9964                        let autoclose_enabled =
 9965                            self.use_autoclose && snapshot_settings.use_autoclose;
 9966                        if autoclose_enabled {
 9967                            let start = snapshot.anchor_after(selection_head);
 9968                            let end = snapshot.anchor_after(selection_head);
 9969                            self.autoclose_regions.push(AutocloseRegion {
 9970                                selection_id: selection.id,
 9971                                range: start..end,
 9972                                pair,
 9973                            });
 9974                        }
 9975                    }
 9976                }
 9977            }
 9978        }
 9979        Ok(())
 9980    }
 9981
 9982    pub fn move_to_next_snippet_tabstop(
 9983        &mut self,
 9984        window: &mut Window,
 9985        cx: &mut Context<Self>,
 9986    ) -> bool {
 9987        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9988    }
 9989
 9990    pub fn move_to_prev_snippet_tabstop(
 9991        &mut self,
 9992        window: &mut Window,
 9993        cx: &mut Context<Self>,
 9994    ) -> bool {
 9995        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9996    }
 9997
 9998    pub fn move_to_snippet_tabstop(
 9999        &mut self,
10000        bias: Bias,
10001        window: &mut Window,
10002        cx: &mut Context<Self>,
10003    ) -> bool {
10004        if let Some(mut snippet) = self.snippet_stack.pop() {
10005            match bias {
10006                Bias::Left => {
10007                    if snippet.active_index > 0 {
10008                        snippet.active_index -= 1;
10009                    } else {
10010                        self.snippet_stack.push(snippet);
10011                        return false;
10012                    }
10013                }
10014                Bias::Right => {
10015                    if snippet.active_index + 1 < snippet.ranges.len() {
10016                        snippet.active_index += 1;
10017                    } else {
10018                        self.snippet_stack.push(snippet);
10019                        return false;
10020                    }
10021                }
10022            }
10023            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10024                self.change_selections(Default::default(), window, cx, |s| {
10025                    // Reverse order so that the first range is the newest created selection.
10026                    // Completions will use it and autoscroll will prioritize it.
10027                    s.select_ranges(current_ranges.iter().rev().cloned())
10028                });
10029
10030                if let Some(choices) = &snippet.choices[snippet.active_index]
10031                    && let Some(selection) = current_ranges.first()
10032                {
10033                    self.show_snippet_choices(choices, selection.clone(), cx);
10034                }
10035
10036                // If snippet state is not at the last tabstop, push it back on the stack
10037                if snippet.active_index + 1 < snippet.ranges.len() {
10038                    self.snippet_stack.push(snippet);
10039                }
10040                return true;
10041            }
10042        }
10043
10044        false
10045    }
10046
10047    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10048        self.transact(window, cx, |this, window, cx| {
10049            this.select_all(&SelectAll, window, cx);
10050            this.insert("", window, cx);
10051        });
10052    }
10053
10054    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10055        if self.read_only(cx) {
10056            return;
10057        }
10058        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10059        self.transact(window, cx, |this, window, cx| {
10060            this.select_autoclose_pair(window, cx);
10061
10062            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10063
10064            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10065            if !this.linked_edit_ranges.is_empty() {
10066                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10067                let snapshot = this.buffer.read(cx).snapshot(cx);
10068
10069                for selection in selections.iter() {
10070                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10071                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10072                    if selection_start.buffer_id != selection_end.buffer_id {
10073                        continue;
10074                    }
10075                    if let Some(ranges) =
10076                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10077                    {
10078                        for (buffer, entries) in ranges {
10079                            linked_ranges.entry(buffer).or_default().extend(entries);
10080                        }
10081                    }
10082                }
10083            }
10084
10085            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10086            for selection in &mut selections {
10087                if selection.is_empty() {
10088                    let old_head = selection.head();
10089                    let mut new_head =
10090                        movement::left(&display_map, old_head.to_display_point(&display_map))
10091                            .to_point(&display_map);
10092                    if let Some((buffer, line_buffer_range)) = display_map
10093                        .buffer_snapshot()
10094                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10095                    {
10096                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10097                        let indent_len = match indent_size.kind {
10098                            IndentKind::Space => {
10099                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10100                            }
10101                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10102                        };
10103                        if old_head.column <= indent_size.len && old_head.column > 0 {
10104                            let indent_len = indent_len.get();
10105                            new_head = cmp::min(
10106                                new_head,
10107                                MultiBufferPoint::new(
10108                                    old_head.row,
10109                                    ((old_head.column - 1) / indent_len) * indent_len,
10110                                ),
10111                            );
10112                        }
10113                    }
10114
10115                    selection.set_head(new_head, SelectionGoal::None);
10116                }
10117            }
10118
10119            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10120            this.insert("", window, cx);
10121            let empty_str: Arc<str> = Arc::from("");
10122            for (buffer, edits) in linked_ranges {
10123                let snapshot = buffer.read(cx).snapshot();
10124                use text::ToPoint as TP;
10125
10126                let edits = edits
10127                    .into_iter()
10128                    .map(|range| {
10129                        let end_point = TP::to_point(&range.end, &snapshot);
10130                        let mut start_point = TP::to_point(&range.start, &snapshot);
10131
10132                        if end_point == start_point {
10133                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10134                                .saturating_sub(1);
10135                            start_point =
10136                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10137                        };
10138
10139                        (start_point..end_point, empty_str.clone())
10140                    })
10141                    .sorted_by_key(|(range, _)| range.start)
10142                    .collect::<Vec<_>>();
10143                buffer.update(cx, |this, cx| {
10144                    this.edit(edits, None, cx);
10145                })
10146            }
10147            this.refresh_edit_prediction(true, false, window, cx);
10148            refresh_linked_ranges(this, window, cx);
10149        });
10150    }
10151
10152    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10153        if self.read_only(cx) {
10154            return;
10155        }
10156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10157        self.transact(window, cx, |this, window, cx| {
10158            this.change_selections(Default::default(), window, cx, |s| {
10159                s.move_with(|map, selection| {
10160                    if selection.is_empty() {
10161                        let cursor = movement::right(map, selection.head());
10162                        selection.end = cursor;
10163                        selection.reversed = true;
10164                        selection.goal = SelectionGoal::None;
10165                    }
10166                })
10167            });
10168            this.insert("", window, cx);
10169            this.refresh_edit_prediction(true, false, window, cx);
10170        });
10171    }
10172
10173    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10174        if self.mode.is_single_line() {
10175            cx.propagate();
10176            return;
10177        }
10178
10179        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10180        if self.move_to_prev_snippet_tabstop(window, cx) {
10181            return;
10182        }
10183        self.outdent(&Outdent, window, cx);
10184    }
10185
10186    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10187        if self.mode.is_single_line() {
10188            cx.propagate();
10189            return;
10190        }
10191
10192        if self.move_to_next_snippet_tabstop(window, cx) {
10193            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10194            return;
10195        }
10196        if self.read_only(cx) {
10197            return;
10198        }
10199        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10200        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10201        let buffer = self.buffer.read(cx);
10202        let snapshot = buffer.snapshot(cx);
10203        let rows_iter = selections.iter().map(|s| s.head().row);
10204        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10205
10206        let has_some_cursor_in_whitespace = selections
10207            .iter()
10208            .filter(|selection| selection.is_empty())
10209            .any(|selection| {
10210                let cursor = selection.head();
10211                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10212                cursor.column < current_indent.len
10213            });
10214
10215        let mut edits = Vec::new();
10216        let mut prev_edited_row = 0;
10217        let mut row_delta = 0;
10218        for selection in &mut selections {
10219            if selection.start.row != prev_edited_row {
10220                row_delta = 0;
10221            }
10222            prev_edited_row = selection.end.row;
10223
10224            // If the selection is non-empty, then increase the indentation of the selected lines.
10225            if !selection.is_empty() {
10226                row_delta =
10227                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10228                continue;
10229            }
10230
10231            let cursor = selection.head();
10232            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10233            if let Some(suggested_indent) =
10234                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10235            {
10236                // Don't do anything if already at suggested indent
10237                // and there is any other cursor which is not
10238                if has_some_cursor_in_whitespace
10239                    && cursor.column == current_indent.len
10240                    && current_indent.len == suggested_indent.len
10241                {
10242                    continue;
10243                }
10244
10245                // Adjust line and move cursor to suggested indent
10246                // if cursor is not at suggested indent
10247                if cursor.column < suggested_indent.len
10248                    && cursor.column <= current_indent.len
10249                    && current_indent.len <= suggested_indent.len
10250                {
10251                    selection.start = Point::new(cursor.row, suggested_indent.len);
10252                    selection.end = selection.start;
10253                    if row_delta == 0 {
10254                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10255                            cursor.row,
10256                            current_indent,
10257                            suggested_indent,
10258                        ));
10259                        row_delta = suggested_indent.len - current_indent.len;
10260                    }
10261                    continue;
10262                }
10263
10264                // If current indent is more than suggested indent
10265                // only move cursor to current indent and skip indent
10266                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10267                    selection.start = Point::new(cursor.row, current_indent.len);
10268                    selection.end = selection.start;
10269                    continue;
10270                }
10271            }
10272
10273            // Otherwise, insert a hard or soft tab.
10274            let settings = buffer.language_settings_at(cursor, cx);
10275            let tab_size = if settings.hard_tabs {
10276                IndentSize::tab()
10277            } else {
10278                let tab_size = settings.tab_size.get();
10279                let indent_remainder = snapshot
10280                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10281                    .flat_map(str::chars)
10282                    .fold(row_delta % tab_size, |counter: u32, c| {
10283                        if c == '\t' {
10284                            0
10285                        } else {
10286                            (counter + 1) % tab_size
10287                        }
10288                    });
10289
10290                let chars_to_next_tab_stop = tab_size - indent_remainder;
10291                IndentSize::spaces(chars_to_next_tab_stop)
10292            };
10293            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10294            selection.end = selection.start;
10295            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10296            row_delta += tab_size.len;
10297        }
10298
10299        self.transact(window, cx, |this, window, cx| {
10300            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10301            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10302            this.refresh_edit_prediction(true, false, window, cx);
10303        });
10304    }
10305
10306    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10307        if self.read_only(cx) {
10308            return;
10309        }
10310        if self.mode.is_single_line() {
10311            cx.propagate();
10312            return;
10313        }
10314
10315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10316        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10317        let mut prev_edited_row = 0;
10318        let mut row_delta = 0;
10319        let mut edits = Vec::new();
10320        let buffer = self.buffer.read(cx);
10321        let snapshot = buffer.snapshot(cx);
10322        for selection in &mut selections {
10323            if selection.start.row != prev_edited_row {
10324                row_delta = 0;
10325            }
10326            prev_edited_row = selection.end.row;
10327
10328            row_delta =
10329                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10330        }
10331
10332        self.transact(window, cx, |this, window, cx| {
10333            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10334            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10335        });
10336    }
10337
10338    fn indent_selection(
10339        buffer: &MultiBuffer,
10340        snapshot: &MultiBufferSnapshot,
10341        selection: &mut Selection<Point>,
10342        edits: &mut Vec<(Range<Point>, String)>,
10343        delta_for_start_row: u32,
10344        cx: &App,
10345    ) -> u32 {
10346        let settings = buffer.language_settings_at(selection.start, cx);
10347        let tab_size = settings.tab_size.get();
10348        let indent_kind = if settings.hard_tabs {
10349            IndentKind::Tab
10350        } else {
10351            IndentKind::Space
10352        };
10353        let mut start_row = selection.start.row;
10354        let mut end_row = selection.end.row + 1;
10355
10356        // If a selection ends at the beginning of a line, don't indent
10357        // that last line.
10358        if selection.end.column == 0 && selection.end.row > selection.start.row {
10359            end_row -= 1;
10360        }
10361
10362        // Avoid re-indenting a row that has already been indented by a
10363        // previous selection, but still update this selection's column
10364        // to reflect that indentation.
10365        if delta_for_start_row > 0 {
10366            start_row += 1;
10367            selection.start.column += delta_for_start_row;
10368            if selection.end.row == selection.start.row {
10369                selection.end.column += delta_for_start_row;
10370            }
10371        }
10372
10373        let mut delta_for_end_row = 0;
10374        let has_multiple_rows = start_row + 1 != end_row;
10375        for row in start_row..end_row {
10376            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10377            let indent_delta = match (current_indent.kind, indent_kind) {
10378                (IndentKind::Space, IndentKind::Space) => {
10379                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10380                    IndentSize::spaces(columns_to_next_tab_stop)
10381                }
10382                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10383                (_, IndentKind::Tab) => IndentSize::tab(),
10384            };
10385
10386            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10387                0
10388            } else {
10389                selection.start.column
10390            };
10391            let row_start = Point::new(row, start);
10392            edits.push((
10393                row_start..row_start,
10394                indent_delta.chars().collect::<String>(),
10395            ));
10396
10397            // Update this selection's endpoints to reflect the indentation.
10398            if row == selection.start.row {
10399                selection.start.column += indent_delta.len;
10400            }
10401            if row == selection.end.row {
10402                selection.end.column += indent_delta.len;
10403                delta_for_end_row = indent_delta.len;
10404            }
10405        }
10406
10407        if selection.start.row == selection.end.row {
10408            delta_for_start_row + delta_for_end_row
10409        } else {
10410            delta_for_end_row
10411        }
10412    }
10413
10414    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10415        if self.read_only(cx) {
10416            return;
10417        }
10418        if self.mode.is_single_line() {
10419            cx.propagate();
10420            return;
10421        }
10422
10423        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10424        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10425        let selections = self.selections.all::<Point>(&display_map);
10426        let mut deletion_ranges = Vec::new();
10427        let mut last_outdent = None;
10428        {
10429            let buffer = self.buffer.read(cx);
10430            let snapshot = buffer.snapshot(cx);
10431            for selection in &selections {
10432                let settings = buffer.language_settings_at(selection.start, cx);
10433                let tab_size = settings.tab_size.get();
10434                let mut rows = selection.spanned_rows(false, &display_map);
10435
10436                // Avoid re-outdenting a row that has already been outdented by a
10437                // previous selection.
10438                if let Some(last_row) = last_outdent
10439                    && last_row == rows.start
10440                {
10441                    rows.start = rows.start.next_row();
10442                }
10443                let has_multiple_rows = rows.len() > 1;
10444                for row in rows.iter_rows() {
10445                    let indent_size = snapshot.indent_size_for_line(row);
10446                    if indent_size.len > 0 {
10447                        let deletion_len = match indent_size.kind {
10448                            IndentKind::Space => {
10449                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10450                                if columns_to_prev_tab_stop == 0 {
10451                                    tab_size
10452                                } else {
10453                                    columns_to_prev_tab_stop
10454                                }
10455                            }
10456                            IndentKind::Tab => 1,
10457                        };
10458                        let start = if has_multiple_rows
10459                            || deletion_len > selection.start.column
10460                            || indent_size.len < selection.start.column
10461                        {
10462                            0
10463                        } else {
10464                            selection.start.column - deletion_len
10465                        };
10466                        deletion_ranges.push(
10467                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10468                        );
10469                        last_outdent = Some(row);
10470                    }
10471                }
10472            }
10473        }
10474
10475        self.transact(window, cx, |this, window, cx| {
10476            this.buffer.update(cx, |buffer, cx| {
10477                let empty_str: Arc<str> = Arc::default();
10478                buffer.edit(
10479                    deletion_ranges
10480                        .into_iter()
10481                        .map(|range| (range, empty_str.clone())),
10482                    None,
10483                    cx,
10484                );
10485            });
10486            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10487            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10488        });
10489    }
10490
10491    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10492        if self.read_only(cx) {
10493            return;
10494        }
10495        if self.mode.is_single_line() {
10496            cx.propagate();
10497            return;
10498        }
10499
10500        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10501        let selections = self
10502            .selections
10503            .all::<usize>(&self.display_snapshot(cx))
10504            .into_iter()
10505            .map(|s| s.range());
10506
10507        self.transact(window, cx, |this, window, cx| {
10508            this.buffer.update(cx, |buffer, cx| {
10509                buffer.autoindent_ranges(selections, cx);
10510            });
10511            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10512            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10513        });
10514    }
10515
10516    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10517        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10518        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10519        let selections = self.selections.all::<Point>(&display_map);
10520
10521        let mut new_cursors = Vec::new();
10522        let mut edit_ranges = Vec::new();
10523        let mut selections = selections.iter().peekable();
10524        while let Some(selection) = selections.next() {
10525            let mut rows = selection.spanned_rows(false, &display_map);
10526
10527            // Accumulate contiguous regions of rows that we want to delete.
10528            while let Some(next_selection) = selections.peek() {
10529                let next_rows = next_selection.spanned_rows(false, &display_map);
10530                if next_rows.start <= rows.end {
10531                    rows.end = next_rows.end;
10532                    selections.next().unwrap();
10533                } else {
10534                    break;
10535                }
10536            }
10537
10538            let buffer = display_map.buffer_snapshot();
10539            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10540            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10541                // If there's a line after the range, delete the \n from the end of the row range
10542                (
10543                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10544                    rows.end,
10545                )
10546            } else {
10547                // If there isn't a line after the range, delete the \n from the line before the
10548                // start of the row range
10549                edit_start = edit_start.saturating_sub(1);
10550                (buffer.len(), rows.start.previous_row())
10551            };
10552
10553            let text_layout_details = self.text_layout_details(window);
10554            let x = display_map.x_for_display_point(
10555                selection.head().to_display_point(&display_map),
10556                &text_layout_details,
10557            );
10558            let row = Point::new(target_row.0, 0)
10559                .to_display_point(&display_map)
10560                .row();
10561            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10562
10563            new_cursors.push((
10564                selection.id,
10565                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10566                SelectionGoal::None,
10567            ));
10568            edit_ranges.push(edit_start..edit_end);
10569        }
10570
10571        self.transact(window, cx, |this, window, cx| {
10572            let buffer = this.buffer.update(cx, |buffer, cx| {
10573                let empty_str: Arc<str> = Arc::default();
10574                buffer.edit(
10575                    edit_ranges
10576                        .into_iter()
10577                        .map(|range| (range, empty_str.clone())),
10578                    None,
10579                    cx,
10580                );
10581                buffer.snapshot(cx)
10582            });
10583            let new_selections = new_cursors
10584                .into_iter()
10585                .map(|(id, cursor, goal)| {
10586                    let cursor = cursor.to_point(&buffer);
10587                    Selection {
10588                        id,
10589                        start: cursor,
10590                        end: cursor,
10591                        reversed: false,
10592                        goal,
10593                    }
10594                })
10595                .collect();
10596
10597            this.change_selections(Default::default(), window, cx, |s| {
10598                s.select(new_selections);
10599            });
10600        });
10601    }
10602
10603    pub fn join_lines_impl(
10604        &mut self,
10605        insert_whitespace: bool,
10606        window: &mut Window,
10607        cx: &mut Context<Self>,
10608    ) {
10609        if self.read_only(cx) {
10610            return;
10611        }
10612        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10613        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10614            let start = MultiBufferRow(selection.start.row);
10615            // Treat single line selections as if they include the next line. Otherwise this action
10616            // would do nothing for single line selections individual cursors.
10617            let end = if selection.start.row == selection.end.row {
10618                MultiBufferRow(selection.start.row + 1)
10619            } else {
10620                MultiBufferRow(selection.end.row)
10621            };
10622
10623            if let Some(last_row_range) = row_ranges.last_mut()
10624                && start <= last_row_range.end
10625            {
10626                last_row_range.end = end;
10627                continue;
10628            }
10629            row_ranges.push(start..end);
10630        }
10631
10632        let snapshot = self.buffer.read(cx).snapshot(cx);
10633        let mut cursor_positions = Vec::new();
10634        for row_range in &row_ranges {
10635            let anchor = snapshot.anchor_before(Point::new(
10636                row_range.end.previous_row().0,
10637                snapshot.line_len(row_range.end.previous_row()),
10638            ));
10639            cursor_positions.push(anchor..anchor);
10640        }
10641
10642        self.transact(window, cx, |this, window, cx| {
10643            for row_range in row_ranges.into_iter().rev() {
10644                for row in row_range.iter_rows().rev() {
10645                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10646                    let next_line_row = row.next_row();
10647                    let indent = snapshot.indent_size_for_line(next_line_row);
10648                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10649
10650                    let replace =
10651                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10652                            " "
10653                        } else {
10654                            ""
10655                        };
10656
10657                    this.buffer.update(cx, |buffer, cx| {
10658                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10659                    });
10660                }
10661            }
10662
10663            this.change_selections(Default::default(), window, cx, |s| {
10664                s.select_anchor_ranges(cursor_positions)
10665            });
10666        });
10667    }
10668
10669    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10670        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10671        self.join_lines_impl(true, window, cx);
10672    }
10673
10674    pub fn sort_lines_case_sensitive(
10675        &mut self,
10676        _: &SortLinesCaseSensitive,
10677        window: &mut Window,
10678        cx: &mut Context<Self>,
10679    ) {
10680        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10681    }
10682
10683    pub fn sort_lines_by_length(
10684        &mut self,
10685        _: &SortLinesByLength,
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.chars().count())
10691        })
10692    }
10693
10694    pub fn sort_lines_case_insensitive(
10695        &mut self,
10696        _: &SortLinesCaseInsensitive,
10697        window: &mut Window,
10698        cx: &mut Context<Self>,
10699    ) {
10700        self.manipulate_immutable_lines(window, cx, |lines| {
10701            lines.sort_by_key(|line| line.to_lowercase())
10702        })
10703    }
10704
10705    pub fn unique_lines_case_insensitive(
10706        &mut self,
10707        _: &UniqueLinesCaseInsensitive,
10708        window: &mut Window,
10709        cx: &mut Context<Self>,
10710    ) {
10711        self.manipulate_immutable_lines(window, cx, |lines| {
10712            let mut seen = HashSet::default();
10713            lines.retain(|line| seen.insert(line.to_lowercase()));
10714        })
10715    }
10716
10717    pub fn unique_lines_case_sensitive(
10718        &mut self,
10719        _: &UniqueLinesCaseSensitive,
10720        window: &mut Window,
10721        cx: &mut Context<Self>,
10722    ) {
10723        self.manipulate_immutable_lines(window, cx, |lines| {
10724            let mut seen = HashSet::default();
10725            lines.retain(|line| seen.insert(*line));
10726        })
10727    }
10728
10729    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10730        let snapshot = self.buffer.read(cx).snapshot(cx);
10731        for selection in self.selections.disjoint_anchors_arc().iter() {
10732            if snapshot
10733                .language_at(selection.start)
10734                .and_then(|lang| lang.config().wrap_characters.as_ref())
10735                .is_some()
10736            {
10737                return true;
10738            }
10739        }
10740        false
10741    }
10742
10743    fn wrap_selections_in_tag(
10744        &mut self,
10745        _: &WrapSelectionsInTag,
10746        window: &mut Window,
10747        cx: &mut Context<Self>,
10748    ) {
10749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10750
10751        let snapshot = self.buffer.read(cx).snapshot(cx);
10752
10753        let mut edits = Vec::new();
10754        let mut boundaries = Vec::new();
10755
10756        for selection in self
10757            .selections
10758            .all::<Point>(&self.display_snapshot(cx))
10759            .iter()
10760        {
10761            let Some(wrap_config) = snapshot
10762                .language_at(selection.start)
10763                .and_then(|lang| lang.config().wrap_characters.clone())
10764            else {
10765                continue;
10766            };
10767
10768            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10769            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10770
10771            let start_before = snapshot.anchor_before(selection.start);
10772            let end_after = snapshot.anchor_after(selection.end);
10773
10774            edits.push((start_before..start_before, open_tag));
10775            edits.push((end_after..end_after, close_tag));
10776
10777            boundaries.push((
10778                start_before,
10779                end_after,
10780                wrap_config.start_prefix.len(),
10781                wrap_config.end_suffix.len(),
10782            ));
10783        }
10784
10785        if edits.is_empty() {
10786            return;
10787        }
10788
10789        self.transact(window, cx, |this, window, cx| {
10790            let buffer = this.buffer.update(cx, |buffer, cx| {
10791                buffer.edit(edits, None, cx);
10792                buffer.snapshot(cx)
10793            });
10794
10795            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10796            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10797                boundaries.into_iter()
10798            {
10799                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10800                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10801                new_selections.push(open_offset..open_offset);
10802                new_selections.push(close_offset..close_offset);
10803            }
10804
10805            this.change_selections(Default::default(), window, cx, |s| {
10806                s.select_ranges(new_selections);
10807            });
10808
10809            this.request_autoscroll(Autoscroll::fit(), cx);
10810        });
10811    }
10812
10813    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10814        let Some(project) = self.project.clone() else {
10815            return;
10816        };
10817        self.reload(project, window, cx)
10818            .detach_and_notify_err(window, cx);
10819    }
10820
10821    pub fn restore_file(
10822        &mut self,
10823        _: &::git::RestoreFile,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) {
10827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10828        let mut buffer_ids = HashSet::default();
10829        let snapshot = self.buffer().read(cx).snapshot(cx);
10830        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10831            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10832        }
10833
10834        let buffer = self.buffer().read(cx);
10835        let ranges = buffer_ids
10836            .into_iter()
10837            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10838            .collect::<Vec<_>>();
10839
10840        self.restore_hunks_in_ranges(ranges, window, cx);
10841    }
10842
10843    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10845        let selections = self
10846            .selections
10847            .all(&self.display_snapshot(cx))
10848            .into_iter()
10849            .map(|s| s.range())
10850            .collect();
10851        self.restore_hunks_in_ranges(selections, window, cx);
10852    }
10853
10854    pub fn restore_hunks_in_ranges(
10855        &mut self,
10856        ranges: Vec<Range<Point>>,
10857        window: &mut Window,
10858        cx: &mut Context<Editor>,
10859    ) {
10860        let mut revert_changes = HashMap::default();
10861        let chunk_by = self
10862            .snapshot(window, cx)
10863            .hunks_for_ranges(ranges)
10864            .into_iter()
10865            .chunk_by(|hunk| hunk.buffer_id);
10866        for (buffer_id, hunks) in &chunk_by {
10867            let hunks = hunks.collect::<Vec<_>>();
10868            for hunk in &hunks {
10869                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10870            }
10871            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10872        }
10873        drop(chunk_by);
10874        if !revert_changes.is_empty() {
10875            self.transact(window, cx, |editor, window, cx| {
10876                editor.restore(revert_changes, window, cx);
10877            });
10878        }
10879    }
10880
10881    pub fn open_active_item_in_terminal(
10882        &mut self,
10883        _: &OpenInTerminal,
10884        window: &mut Window,
10885        cx: &mut Context<Self>,
10886    ) {
10887        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10888            let project_path = buffer.read(cx).project_path(cx)?;
10889            let project = self.project()?.read(cx);
10890            let entry = project.entry_for_path(&project_path, cx)?;
10891            let parent = match &entry.canonical_path {
10892                Some(canonical_path) => canonical_path.to_path_buf(),
10893                None => project.absolute_path(&project_path, cx)?,
10894            }
10895            .parent()?
10896            .to_path_buf();
10897            Some(parent)
10898        }) {
10899            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10900        }
10901    }
10902
10903    fn set_breakpoint_context_menu(
10904        &mut self,
10905        display_row: DisplayRow,
10906        position: Option<Anchor>,
10907        clicked_point: gpui::Point<Pixels>,
10908        window: &mut Window,
10909        cx: &mut Context<Self>,
10910    ) {
10911        let source = self
10912            .buffer
10913            .read(cx)
10914            .snapshot(cx)
10915            .anchor_before(Point::new(display_row.0, 0u32));
10916
10917        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10918
10919        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10920            self,
10921            source,
10922            clicked_point,
10923            context_menu,
10924            window,
10925            cx,
10926        );
10927    }
10928
10929    fn add_edit_breakpoint_block(
10930        &mut self,
10931        anchor: Anchor,
10932        breakpoint: &Breakpoint,
10933        edit_action: BreakpointPromptEditAction,
10934        window: &mut Window,
10935        cx: &mut Context<Self>,
10936    ) {
10937        let weak_editor = cx.weak_entity();
10938        let bp_prompt = cx.new(|cx| {
10939            BreakpointPromptEditor::new(
10940                weak_editor,
10941                anchor,
10942                breakpoint.clone(),
10943                edit_action,
10944                window,
10945                cx,
10946            )
10947        });
10948
10949        let height = bp_prompt.update(cx, |this, cx| {
10950            this.prompt
10951                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10952        });
10953        let cloned_prompt = bp_prompt.clone();
10954        let blocks = vec![BlockProperties {
10955            style: BlockStyle::Sticky,
10956            placement: BlockPlacement::Above(anchor),
10957            height: Some(height),
10958            render: Arc::new(move |cx| {
10959                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10960                cloned_prompt.clone().into_any_element()
10961            }),
10962            priority: 0,
10963        }];
10964
10965        let focus_handle = bp_prompt.focus_handle(cx);
10966        window.focus(&focus_handle);
10967
10968        let block_ids = self.insert_blocks(blocks, None, cx);
10969        bp_prompt.update(cx, |prompt, _| {
10970            prompt.add_block_ids(block_ids);
10971        });
10972    }
10973
10974    pub(crate) fn breakpoint_at_row(
10975        &self,
10976        row: u32,
10977        window: &mut Window,
10978        cx: &mut Context<Self>,
10979    ) -> Option<(Anchor, Breakpoint)> {
10980        let snapshot = self.snapshot(window, cx);
10981        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10982
10983        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10984    }
10985
10986    pub(crate) fn breakpoint_at_anchor(
10987        &self,
10988        breakpoint_position: Anchor,
10989        snapshot: &EditorSnapshot,
10990        cx: &mut Context<Self>,
10991    ) -> Option<(Anchor, Breakpoint)> {
10992        let buffer = self
10993            .buffer
10994            .read(cx)
10995            .buffer_for_anchor(breakpoint_position, cx)?;
10996
10997        let enclosing_excerpt = breakpoint_position.excerpt_id;
10998        let buffer_snapshot = buffer.read(cx).snapshot();
10999
11000        let row = buffer_snapshot
11001            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11002            .row;
11003
11004        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11005        let anchor_end = snapshot
11006            .buffer_snapshot()
11007            .anchor_after(Point::new(row, line_len));
11008
11009        self.breakpoint_store
11010            .as_ref()?
11011            .read_with(cx, |breakpoint_store, cx| {
11012                breakpoint_store
11013                    .breakpoints(
11014                        &buffer,
11015                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11016                        &buffer_snapshot,
11017                        cx,
11018                    )
11019                    .next()
11020                    .and_then(|(bp, _)| {
11021                        let breakpoint_row = buffer_snapshot
11022                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11023                            .row;
11024
11025                        if breakpoint_row == row {
11026                            snapshot
11027                                .buffer_snapshot()
11028                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11029                                .map(|position| (position, bp.bp.clone()))
11030                        } else {
11031                            None
11032                        }
11033                    })
11034            })
11035    }
11036
11037    pub fn edit_log_breakpoint(
11038        &mut self,
11039        _: &EditLogBreakpoint,
11040        window: &mut Window,
11041        cx: &mut Context<Self>,
11042    ) {
11043        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11044            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11045                message: None,
11046                state: BreakpointState::Enabled,
11047                condition: None,
11048                hit_condition: None,
11049            });
11050
11051            self.add_edit_breakpoint_block(
11052                anchor,
11053                &breakpoint,
11054                BreakpointPromptEditAction::Log,
11055                window,
11056                cx,
11057            );
11058        }
11059    }
11060
11061    fn breakpoints_at_cursors(
11062        &self,
11063        window: &mut Window,
11064        cx: &mut Context<Self>,
11065    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11066        let snapshot = self.snapshot(window, cx);
11067        let cursors = self
11068            .selections
11069            .disjoint_anchors_arc()
11070            .iter()
11071            .map(|selection| {
11072                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11073
11074                let breakpoint_position = self
11075                    .breakpoint_at_row(cursor_position.row, window, cx)
11076                    .map(|bp| bp.0)
11077                    .unwrap_or_else(|| {
11078                        snapshot
11079                            .display_snapshot
11080                            .buffer_snapshot()
11081                            .anchor_after(Point::new(cursor_position.row, 0))
11082                    });
11083
11084                let breakpoint = self
11085                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11086                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11087
11088                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11089            })
11090            // 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.
11091            .collect::<HashMap<Anchor, _>>();
11092
11093        cursors.into_iter().collect()
11094    }
11095
11096    pub fn enable_breakpoint(
11097        &mut self,
11098        _: &crate::actions::EnableBreakpoint,
11099        window: &mut Window,
11100        cx: &mut Context<Self>,
11101    ) {
11102        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11103            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11104                continue;
11105            };
11106            self.edit_breakpoint_at_anchor(
11107                anchor,
11108                breakpoint,
11109                BreakpointEditAction::InvertState,
11110                cx,
11111            );
11112        }
11113    }
11114
11115    pub fn disable_breakpoint(
11116        &mut self,
11117        _: &crate::actions::DisableBreakpoint,
11118        window: &mut Window,
11119        cx: &mut Context<Self>,
11120    ) {
11121        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11122            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11123                continue;
11124            };
11125            self.edit_breakpoint_at_anchor(
11126                anchor,
11127                breakpoint,
11128                BreakpointEditAction::InvertState,
11129                cx,
11130            );
11131        }
11132    }
11133
11134    pub fn toggle_breakpoint(
11135        &mut self,
11136        _: &crate::actions::ToggleBreakpoint,
11137        window: &mut Window,
11138        cx: &mut Context<Self>,
11139    ) {
11140        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11141            if let Some(breakpoint) = breakpoint {
11142                self.edit_breakpoint_at_anchor(
11143                    anchor,
11144                    breakpoint,
11145                    BreakpointEditAction::Toggle,
11146                    cx,
11147                );
11148            } else {
11149                self.edit_breakpoint_at_anchor(
11150                    anchor,
11151                    Breakpoint::new_standard(),
11152                    BreakpointEditAction::Toggle,
11153                    cx,
11154                );
11155            }
11156        }
11157    }
11158
11159    pub fn edit_breakpoint_at_anchor(
11160        &mut self,
11161        breakpoint_position: Anchor,
11162        breakpoint: Breakpoint,
11163        edit_action: BreakpointEditAction,
11164        cx: &mut Context<Self>,
11165    ) {
11166        let Some(breakpoint_store) = &self.breakpoint_store else {
11167            return;
11168        };
11169
11170        let Some(buffer) = self
11171            .buffer
11172            .read(cx)
11173            .buffer_for_anchor(breakpoint_position, cx)
11174        else {
11175            return;
11176        };
11177
11178        breakpoint_store.update(cx, |breakpoint_store, cx| {
11179            breakpoint_store.toggle_breakpoint(
11180                buffer,
11181                BreakpointWithPosition {
11182                    position: breakpoint_position.text_anchor,
11183                    bp: breakpoint,
11184                },
11185                edit_action,
11186                cx,
11187            );
11188        });
11189
11190        cx.notify();
11191    }
11192
11193    #[cfg(any(test, feature = "test-support"))]
11194    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11195        self.breakpoint_store.clone()
11196    }
11197
11198    pub fn prepare_restore_change(
11199        &self,
11200        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11201        hunk: &MultiBufferDiffHunk,
11202        cx: &mut App,
11203    ) -> Option<()> {
11204        if hunk.is_created_file() {
11205            return None;
11206        }
11207        let buffer = self.buffer.read(cx);
11208        let diff = buffer.diff_for(hunk.buffer_id)?;
11209        let buffer = buffer.buffer(hunk.buffer_id)?;
11210        let buffer = buffer.read(cx);
11211        let original_text = diff
11212            .read(cx)
11213            .base_text()
11214            .as_rope()
11215            .slice(hunk.diff_base_byte_range.clone());
11216        let buffer_snapshot = buffer.snapshot();
11217        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11218        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11219            probe
11220                .0
11221                .start
11222                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11223                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11224        }) {
11225            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11226            Some(())
11227        } else {
11228            None
11229        }
11230    }
11231
11232    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11233        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11234    }
11235
11236    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11237        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11238    }
11239
11240    fn manipulate_lines<M>(
11241        &mut self,
11242        window: &mut Window,
11243        cx: &mut Context<Self>,
11244        mut manipulate: M,
11245    ) where
11246        M: FnMut(&str) -> LineManipulationResult,
11247    {
11248        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11249
11250        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11251        let buffer = self.buffer.read(cx).snapshot(cx);
11252
11253        let mut edits = Vec::new();
11254
11255        let selections = self.selections.all::<Point>(&display_map);
11256        let mut selections = selections.iter().peekable();
11257        let mut contiguous_row_selections = Vec::new();
11258        let mut new_selections = Vec::new();
11259        let mut added_lines = 0;
11260        let mut removed_lines = 0;
11261
11262        while let Some(selection) = selections.next() {
11263            let (start_row, end_row) = consume_contiguous_rows(
11264                &mut contiguous_row_selections,
11265                selection,
11266                &display_map,
11267                &mut selections,
11268            );
11269
11270            let start_point = Point::new(start_row.0, 0);
11271            let end_point = Point::new(
11272                end_row.previous_row().0,
11273                buffer.line_len(end_row.previous_row()),
11274            );
11275            let text = buffer
11276                .text_for_range(start_point..end_point)
11277                .collect::<String>();
11278
11279            let LineManipulationResult {
11280                new_text,
11281                line_count_before,
11282                line_count_after,
11283            } = manipulate(&text);
11284
11285            edits.push((start_point..end_point, new_text));
11286
11287            // Selections must change based on added and removed line count
11288            let start_row =
11289                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11290            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11291            new_selections.push(Selection {
11292                id: selection.id,
11293                start: start_row,
11294                end: end_row,
11295                goal: SelectionGoal::None,
11296                reversed: selection.reversed,
11297            });
11298
11299            if line_count_after > line_count_before {
11300                added_lines += line_count_after - line_count_before;
11301            } else if line_count_before > line_count_after {
11302                removed_lines += line_count_before - line_count_after;
11303            }
11304        }
11305
11306        self.transact(window, cx, |this, window, cx| {
11307            let buffer = this.buffer.update(cx, |buffer, cx| {
11308                buffer.edit(edits, None, cx);
11309                buffer.snapshot(cx)
11310            });
11311
11312            // Recalculate offsets on newly edited buffer
11313            let new_selections = new_selections
11314                .iter()
11315                .map(|s| {
11316                    let start_point = Point::new(s.start.0, 0);
11317                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11318                    Selection {
11319                        id: s.id,
11320                        start: buffer.point_to_offset(start_point),
11321                        end: buffer.point_to_offset(end_point),
11322                        goal: s.goal,
11323                        reversed: s.reversed,
11324                    }
11325                })
11326                .collect();
11327
11328            this.change_selections(Default::default(), window, cx, |s| {
11329                s.select(new_selections);
11330            });
11331
11332            this.request_autoscroll(Autoscroll::fit(), cx);
11333        });
11334    }
11335
11336    fn manipulate_immutable_lines<Fn>(
11337        &mut self,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340        mut callback: Fn,
11341    ) where
11342        Fn: FnMut(&mut Vec<&str>),
11343    {
11344        self.manipulate_lines(window, cx, |text| {
11345            let mut lines: Vec<&str> = text.split('\n').collect();
11346            let line_count_before = lines.len();
11347
11348            callback(&mut lines);
11349
11350            LineManipulationResult {
11351                new_text: lines.join("\n"),
11352                line_count_before,
11353                line_count_after: lines.len(),
11354            }
11355        });
11356    }
11357
11358    fn manipulate_mutable_lines<Fn>(
11359        &mut self,
11360        window: &mut Window,
11361        cx: &mut Context<Self>,
11362        mut callback: Fn,
11363    ) where
11364        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11365    {
11366        self.manipulate_lines(window, cx, |text| {
11367            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11368            let line_count_before = lines.len();
11369
11370            callback(&mut lines);
11371
11372            LineManipulationResult {
11373                new_text: lines.join("\n"),
11374                line_count_before,
11375                line_count_after: lines.len(),
11376            }
11377        });
11378    }
11379
11380    pub fn convert_indentation_to_spaces(
11381        &mut self,
11382        _: &ConvertIndentationToSpaces,
11383        window: &mut Window,
11384        cx: &mut Context<Self>,
11385    ) {
11386        let settings = self.buffer.read(cx).language_settings(cx);
11387        let tab_size = settings.tab_size.get() as usize;
11388
11389        self.manipulate_mutable_lines(window, cx, |lines| {
11390            // Allocates a reasonably sized scratch buffer once for the whole loop
11391            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11392            // Avoids recomputing spaces that could be inserted many times
11393            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11394                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11395                .collect();
11396
11397            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11398                let mut chars = line.as_ref().chars();
11399                let mut col = 0;
11400                let mut changed = false;
11401
11402                for ch in chars.by_ref() {
11403                    match ch {
11404                        ' ' => {
11405                            reindented_line.push(' ');
11406                            col += 1;
11407                        }
11408                        '\t' => {
11409                            // \t are converted to spaces depending on the current column
11410                            let spaces_len = tab_size - (col % tab_size);
11411                            reindented_line.extend(&space_cache[spaces_len - 1]);
11412                            col += spaces_len;
11413                            changed = true;
11414                        }
11415                        _ => {
11416                            // If we dont append before break, the character is consumed
11417                            reindented_line.push(ch);
11418                            break;
11419                        }
11420                    }
11421                }
11422
11423                if !changed {
11424                    reindented_line.clear();
11425                    continue;
11426                }
11427                // Append the rest of the line and replace old reference with new one
11428                reindented_line.extend(chars);
11429                *line = Cow::Owned(reindented_line.clone());
11430                reindented_line.clear();
11431            }
11432        });
11433    }
11434
11435    pub fn convert_indentation_to_tabs(
11436        &mut self,
11437        _: &ConvertIndentationToTabs,
11438        window: &mut Window,
11439        cx: &mut Context<Self>,
11440    ) {
11441        let settings = self.buffer.read(cx).language_settings(cx);
11442        let tab_size = settings.tab_size.get() as usize;
11443
11444        self.manipulate_mutable_lines(window, cx, |lines| {
11445            // Allocates a reasonably sized buffer once for the whole loop
11446            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11447            // Avoids recomputing spaces that could be inserted many times
11448            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11449                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11450                .collect();
11451
11452            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11453                let mut chars = line.chars();
11454                let mut spaces_count = 0;
11455                let mut first_non_indent_char = None;
11456                let mut changed = false;
11457
11458                for ch in chars.by_ref() {
11459                    match ch {
11460                        ' ' => {
11461                            // Keep track of spaces. Append \t when we reach tab_size
11462                            spaces_count += 1;
11463                            changed = true;
11464                            if spaces_count == tab_size {
11465                                reindented_line.push('\t');
11466                                spaces_count = 0;
11467                            }
11468                        }
11469                        '\t' => {
11470                            reindented_line.push('\t');
11471                            spaces_count = 0;
11472                        }
11473                        _ => {
11474                            // Dont append it yet, we might have remaining spaces
11475                            first_non_indent_char = Some(ch);
11476                            break;
11477                        }
11478                    }
11479                }
11480
11481                if !changed {
11482                    reindented_line.clear();
11483                    continue;
11484                }
11485                // Remaining spaces that didn't make a full tab stop
11486                if spaces_count > 0 {
11487                    reindented_line.extend(&space_cache[spaces_count - 1]);
11488                }
11489                // If we consume an extra character that was not indentation, add it back
11490                if let Some(extra_char) = first_non_indent_char {
11491                    reindented_line.push(extra_char);
11492                }
11493                // Append the rest of the line and replace old reference with new one
11494                reindented_line.extend(chars);
11495                *line = Cow::Owned(reindented_line.clone());
11496                reindented_line.clear();
11497            }
11498        });
11499    }
11500
11501    pub fn convert_to_upper_case(
11502        &mut self,
11503        _: &ConvertToUpperCase,
11504        window: &mut Window,
11505        cx: &mut Context<Self>,
11506    ) {
11507        self.manipulate_text(window, cx, |text| text.to_uppercase())
11508    }
11509
11510    pub fn convert_to_lower_case(
11511        &mut self,
11512        _: &ConvertToLowerCase,
11513        window: &mut Window,
11514        cx: &mut Context<Self>,
11515    ) {
11516        self.manipulate_text(window, cx, |text| text.to_lowercase())
11517    }
11518
11519    pub fn convert_to_title_case(
11520        &mut self,
11521        _: &ConvertToTitleCase,
11522        window: &mut Window,
11523        cx: &mut Context<Self>,
11524    ) {
11525        self.manipulate_text(window, cx, |text| {
11526            text.split('\n')
11527                .map(|line| line.to_case(Case::Title))
11528                .join("\n")
11529        })
11530    }
11531
11532    pub fn convert_to_snake_case(
11533        &mut self,
11534        _: &ConvertToSnakeCase,
11535        window: &mut Window,
11536        cx: &mut Context<Self>,
11537    ) {
11538        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11539    }
11540
11541    pub fn convert_to_kebab_case(
11542        &mut self,
11543        _: &ConvertToKebabCase,
11544        window: &mut Window,
11545        cx: &mut Context<Self>,
11546    ) {
11547        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11548    }
11549
11550    pub fn convert_to_upper_camel_case(
11551        &mut self,
11552        _: &ConvertToUpperCamelCase,
11553        window: &mut Window,
11554        cx: &mut Context<Self>,
11555    ) {
11556        self.manipulate_text(window, cx, |text| {
11557            text.split('\n')
11558                .map(|line| line.to_case(Case::UpperCamel))
11559                .join("\n")
11560        })
11561    }
11562
11563    pub fn convert_to_lower_camel_case(
11564        &mut self,
11565        _: &ConvertToLowerCamelCase,
11566        window: &mut Window,
11567        cx: &mut Context<Self>,
11568    ) {
11569        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11570    }
11571
11572    pub fn convert_to_opposite_case(
11573        &mut self,
11574        _: &ConvertToOppositeCase,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.manipulate_text(window, cx, |text| {
11579            text.chars()
11580                .fold(String::with_capacity(text.len()), |mut t, c| {
11581                    if c.is_uppercase() {
11582                        t.extend(c.to_lowercase());
11583                    } else {
11584                        t.extend(c.to_uppercase());
11585                    }
11586                    t
11587                })
11588        })
11589    }
11590
11591    pub fn convert_to_sentence_case(
11592        &mut self,
11593        _: &ConvertToSentenceCase,
11594        window: &mut Window,
11595        cx: &mut Context<Self>,
11596    ) {
11597        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11598    }
11599
11600    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11601        self.manipulate_text(window, cx, |text| {
11602            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11603            if has_upper_case_characters {
11604                text.to_lowercase()
11605            } else {
11606                text.to_uppercase()
11607            }
11608        })
11609    }
11610
11611    pub fn convert_to_rot13(
11612        &mut self,
11613        _: &ConvertToRot13,
11614        window: &mut Window,
11615        cx: &mut Context<Self>,
11616    ) {
11617        self.manipulate_text(window, cx, |text| {
11618            text.chars()
11619                .map(|c| match c {
11620                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11621                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11622                    _ => c,
11623                })
11624                .collect()
11625        })
11626    }
11627
11628    pub fn convert_to_rot47(
11629        &mut self,
11630        _: &ConvertToRot47,
11631        window: &mut Window,
11632        cx: &mut Context<Self>,
11633    ) {
11634        self.manipulate_text(window, cx, |text| {
11635            text.chars()
11636                .map(|c| {
11637                    let code_point = c as u32;
11638                    if code_point >= 33 && code_point <= 126 {
11639                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11640                    }
11641                    c
11642                })
11643                .collect()
11644        })
11645    }
11646
11647    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11648    where
11649        Fn: FnMut(&str) -> String,
11650    {
11651        let buffer = self.buffer.read(cx).snapshot(cx);
11652
11653        let mut new_selections = Vec::new();
11654        let mut edits = Vec::new();
11655        let mut selection_adjustment = 0i32;
11656
11657        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11658            let selection_is_empty = selection.is_empty();
11659
11660            let (start, end) = if selection_is_empty {
11661                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11662                (word_range.start, word_range.end)
11663            } else {
11664                (
11665                    buffer.point_to_offset(selection.start),
11666                    buffer.point_to_offset(selection.end),
11667                )
11668            };
11669
11670            let text = buffer.text_for_range(start..end).collect::<String>();
11671            let old_length = text.len() as i32;
11672            let text = callback(&text);
11673
11674            new_selections.push(Selection {
11675                start: (start as i32 - selection_adjustment) as usize,
11676                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11677                goal: SelectionGoal::None,
11678                id: selection.id,
11679                reversed: selection.reversed,
11680            });
11681
11682            selection_adjustment += old_length - text.len() as i32;
11683
11684            edits.push((start..end, text));
11685        }
11686
11687        self.transact(window, cx, |this, window, cx| {
11688            this.buffer.update(cx, |buffer, cx| {
11689                buffer.edit(edits, None, cx);
11690            });
11691
11692            this.change_selections(Default::default(), window, cx, |s| {
11693                s.select(new_selections);
11694            });
11695
11696            this.request_autoscroll(Autoscroll::fit(), cx);
11697        });
11698    }
11699
11700    pub fn move_selection_on_drop(
11701        &mut self,
11702        selection: &Selection<Anchor>,
11703        target: DisplayPoint,
11704        is_cut: bool,
11705        window: &mut Window,
11706        cx: &mut Context<Self>,
11707    ) {
11708        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11709        let buffer = display_map.buffer_snapshot();
11710        let mut edits = Vec::new();
11711        let insert_point = display_map
11712            .clip_point(target, Bias::Left)
11713            .to_point(&display_map);
11714        let text = buffer
11715            .text_for_range(selection.start..selection.end)
11716            .collect::<String>();
11717        if is_cut {
11718            edits.push(((selection.start..selection.end), String::new()));
11719        }
11720        let insert_anchor = buffer.anchor_before(insert_point);
11721        edits.push(((insert_anchor..insert_anchor), text));
11722        let last_edit_start = insert_anchor.bias_left(buffer);
11723        let last_edit_end = insert_anchor.bias_right(buffer);
11724        self.transact(window, cx, |this, window, cx| {
11725            this.buffer.update(cx, |buffer, cx| {
11726                buffer.edit(edits, None, cx);
11727            });
11728            this.change_selections(Default::default(), window, cx, |s| {
11729                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11730            });
11731        });
11732    }
11733
11734    pub fn clear_selection_drag_state(&mut self) {
11735        self.selection_drag_state = SelectionDragState::None;
11736    }
11737
11738    pub fn duplicate(
11739        &mut self,
11740        upwards: bool,
11741        whole_lines: bool,
11742        window: &mut Window,
11743        cx: &mut Context<Self>,
11744    ) {
11745        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11746
11747        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11748        let buffer = display_map.buffer_snapshot();
11749        let selections = self.selections.all::<Point>(&display_map);
11750
11751        let mut edits = Vec::new();
11752        let mut selections_iter = selections.iter().peekable();
11753        while let Some(selection) = selections_iter.next() {
11754            let mut rows = selection.spanned_rows(false, &display_map);
11755            // duplicate line-wise
11756            if whole_lines || selection.start == selection.end {
11757                // Avoid duplicating the same lines twice.
11758                while let Some(next_selection) = selections_iter.peek() {
11759                    let next_rows = next_selection.spanned_rows(false, &display_map);
11760                    if next_rows.start < rows.end {
11761                        rows.end = next_rows.end;
11762                        selections_iter.next().unwrap();
11763                    } else {
11764                        break;
11765                    }
11766                }
11767
11768                // Copy the text from the selected row region and splice it either at the start
11769                // or end of the region.
11770                let start = Point::new(rows.start.0, 0);
11771                let end = Point::new(
11772                    rows.end.previous_row().0,
11773                    buffer.line_len(rows.end.previous_row()),
11774                );
11775
11776                let mut text = buffer.text_for_range(start..end).collect::<String>();
11777
11778                let insert_location = if upwards {
11779                    // When duplicating upward, we need to insert before the current line.
11780                    // If we're on the last line and it doesn't end with a newline,
11781                    // we need to add a newline before the duplicated content.
11782                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11783                        && buffer.max_point().column > 0
11784                        && !text.ends_with('\n');
11785
11786                    if needs_leading_newline {
11787                        text.insert(0, '\n');
11788                        end
11789                    } else {
11790                        text.push('\n');
11791                        Point::new(rows.end.0, 0)
11792                    }
11793                } else {
11794                    text.push('\n');
11795                    start
11796                };
11797                edits.push((insert_location..insert_location, text));
11798            } else {
11799                // duplicate character-wise
11800                let start = selection.start;
11801                let end = selection.end;
11802                let text = buffer.text_for_range(start..end).collect::<String>();
11803                edits.push((selection.end..selection.end, text));
11804            }
11805        }
11806
11807        self.transact(window, cx, |this, _, cx| {
11808            this.buffer.update(cx, |buffer, cx| {
11809                buffer.edit(edits, None, cx);
11810            });
11811
11812            this.request_autoscroll(Autoscroll::fit(), cx);
11813        });
11814    }
11815
11816    pub fn duplicate_line_up(
11817        &mut self,
11818        _: &DuplicateLineUp,
11819        window: &mut Window,
11820        cx: &mut Context<Self>,
11821    ) {
11822        self.duplicate(true, true, window, cx);
11823    }
11824
11825    pub fn duplicate_line_down(
11826        &mut self,
11827        _: &DuplicateLineDown,
11828        window: &mut Window,
11829        cx: &mut Context<Self>,
11830    ) {
11831        self.duplicate(false, true, window, cx);
11832    }
11833
11834    pub fn duplicate_selection(
11835        &mut self,
11836        _: &DuplicateSelection,
11837        window: &mut Window,
11838        cx: &mut Context<Self>,
11839    ) {
11840        self.duplicate(false, false, window, cx);
11841    }
11842
11843    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11845        if self.mode.is_single_line() {
11846            cx.propagate();
11847            return;
11848        }
11849
11850        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11851        let buffer = self.buffer.read(cx).snapshot(cx);
11852
11853        let mut edits = Vec::new();
11854        let mut unfold_ranges = Vec::new();
11855        let mut refold_creases = Vec::new();
11856
11857        let selections = self.selections.all::<Point>(&display_map);
11858        let mut selections = selections.iter().peekable();
11859        let mut contiguous_row_selections = Vec::new();
11860        let mut new_selections = Vec::new();
11861
11862        while let Some(selection) = selections.next() {
11863            // Find all the selections that span a contiguous row range
11864            let (start_row, end_row) = consume_contiguous_rows(
11865                &mut contiguous_row_selections,
11866                selection,
11867                &display_map,
11868                &mut selections,
11869            );
11870
11871            // Move the text spanned by the row range to be before the line preceding the row range
11872            if start_row.0 > 0 {
11873                let range_to_move = Point::new(
11874                    start_row.previous_row().0,
11875                    buffer.line_len(start_row.previous_row()),
11876                )
11877                    ..Point::new(
11878                        end_row.previous_row().0,
11879                        buffer.line_len(end_row.previous_row()),
11880                    );
11881                let insertion_point = display_map
11882                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11883                    .0;
11884
11885                // Don't move lines across excerpts
11886                if buffer
11887                    .excerpt_containing(insertion_point..range_to_move.end)
11888                    .is_some()
11889                {
11890                    let text = buffer
11891                        .text_for_range(range_to_move.clone())
11892                        .flat_map(|s| s.chars())
11893                        .skip(1)
11894                        .chain(['\n'])
11895                        .collect::<String>();
11896
11897                    edits.push((
11898                        buffer.anchor_after(range_to_move.start)
11899                            ..buffer.anchor_before(range_to_move.end),
11900                        String::new(),
11901                    ));
11902                    let insertion_anchor = buffer.anchor_after(insertion_point);
11903                    edits.push((insertion_anchor..insertion_anchor, text));
11904
11905                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11906
11907                    // Move selections up
11908                    new_selections.extend(contiguous_row_selections.drain(..).map(
11909                        |mut selection| {
11910                            selection.start.row -= row_delta;
11911                            selection.end.row -= row_delta;
11912                            selection
11913                        },
11914                    ));
11915
11916                    // Move folds up
11917                    unfold_ranges.push(range_to_move.clone());
11918                    for fold in display_map.folds_in_range(
11919                        buffer.anchor_before(range_to_move.start)
11920                            ..buffer.anchor_after(range_to_move.end),
11921                    ) {
11922                        let mut start = fold.range.start.to_point(&buffer);
11923                        let mut end = fold.range.end.to_point(&buffer);
11924                        start.row -= row_delta;
11925                        end.row -= row_delta;
11926                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11927                    }
11928                }
11929            }
11930
11931            // If we didn't move line(s), preserve the existing selections
11932            new_selections.append(&mut contiguous_row_selections);
11933        }
11934
11935        self.transact(window, cx, |this, window, cx| {
11936            this.unfold_ranges(&unfold_ranges, true, true, cx);
11937            this.buffer.update(cx, |buffer, cx| {
11938                for (range, text) in edits {
11939                    buffer.edit([(range, text)], None, cx);
11940                }
11941            });
11942            this.fold_creases(refold_creases, true, window, cx);
11943            this.change_selections(Default::default(), window, cx, |s| {
11944                s.select(new_selections);
11945            })
11946        });
11947    }
11948
11949    pub fn move_line_down(
11950        &mut self,
11951        _: &MoveLineDown,
11952        window: &mut Window,
11953        cx: &mut Context<Self>,
11954    ) {
11955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11956        if self.mode.is_single_line() {
11957            cx.propagate();
11958            return;
11959        }
11960
11961        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11962        let buffer = self.buffer.read(cx).snapshot(cx);
11963
11964        let mut edits = Vec::new();
11965        let mut unfold_ranges = Vec::new();
11966        let mut refold_creases = Vec::new();
11967
11968        let selections = self.selections.all::<Point>(&display_map);
11969        let mut selections = selections.iter().peekable();
11970        let mut contiguous_row_selections = Vec::new();
11971        let mut new_selections = Vec::new();
11972
11973        while let Some(selection) = selections.next() {
11974            // Find all the selections that span a contiguous row range
11975            let (start_row, end_row) = consume_contiguous_rows(
11976                &mut contiguous_row_selections,
11977                selection,
11978                &display_map,
11979                &mut selections,
11980            );
11981
11982            // Move the text spanned by the row range to be after the last line of the row range
11983            if end_row.0 <= buffer.max_point().row {
11984                let range_to_move =
11985                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11986                let insertion_point = display_map
11987                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11988                    .0;
11989
11990                // Don't move lines across excerpt boundaries
11991                if buffer
11992                    .excerpt_containing(range_to_move.start..insertion_point)
11993                    .is_some()
11994                {
11995                    let mut text = String::from("\n");
11996                    text.extend(buffer.text_for_range(range_to_move.clone()));
11997                    text.pop(); // Drop trailing newline
11998                    edits.push((
11999                        buffer.anchor_after(range_to_move.start)
12000                            ..buffer.anchor_before(range_to_move.end),
12001                        String::new(),
12002                    ));
12003                    let insertion_anchor = buffer.anchor_after(insertion_point);
12004                    edits.push((insertion_anchor..insertion_anchor, text));
12005
12006                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12007
12008                    // Move selections down
12009                    new_selections.extend(contiguous_row_selections.drain(..).map(
12010                        |mut selection| {
12011                            selection.start.row += row_delta;
12012                            selection.end.row += row_delta;
12013                            selection
12014                        },
12015                    ));
12016
12017                    // Move folds down
12018                    unfold_ranges.push(range_to_move.clone());
12019                    for fold in display_map.folds_in_range(
12020                        buffer.anchor_before(range_to_move.start)
12021                            ..buffer.anchor_after(range_to_move.end),
12022                    ) {
12023                        let mut start = fold.range.start.to_point(&buffer);
12024                        let mut end = fold.range.end.to_point(&buffer);
12025                        start.row += row_delta;
12026                        end.row += row_delta;
12027                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12028                    }
12029                }
12030            }
12031
12032            // If we didn't move line(s), preserve the existing selections
12033            new_selections.append(&mut contiguous_row_selections);
12034        }
12035
12036        self.transact(window, cx, |this, window, cx| {
12037            this.unfold_ranges(&unfold_ranges, true, true, cx);
12038            this.buffer.update(cx, |buffer, cx| {
12039                for (range, text) in edits {
12040                    buffer.edit([(range, text)], None, cx);
12041                }
12042            });
12043            this.fold_creases(refold_creases, true, window, cx);
12044            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12045        });
12046    }
12047
12048    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12049        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12050        let text_layout_details = &self.text_layout_details(window);
12051        self.transact(window, cx, |this, window, cx| {
12052            let edits = this.change_selections(Default::default(), window, cx, |s| {
12053                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12054                s.move_with(|display_map, selection| {
12055                    if !selection.is_empty() {
12056                        return;
12057                    }
12058
12059                    let mut head = selection.head();
12060                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12061                    if head.column() == display_map.line_len(head.row()) {
12062                        transpose_offset = display_map
12063                            .buffer_snapshot()
12064                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12065                    }
12066
12067                    if transpose_offset == 0 {
12068                        return;
12069                    }
12070
12071                    *head.column_mut() += 1;
12072                    head = display_map.clip_point(head, Bias::Right);
12073                    let goal = SelectionGoal::HorizontalPosition(
12074                        display_map
12075                            .x_for_display_point(head, text_layout_details)
12076                            .into(),
12077                    );
12078                    selection.collapse_to(head, goal);
12079
12080                    let transpose_start = display_map
12081                        .buffer_snapshot()
12082                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12083                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12084                        let transpose_end = display_map
12085                            .buffer_snapshot()
12086                            .clip_offset(transpose_offset + 1, Bias::Right);
12087                        if let Some(ch) = display_map
12088                            .buffer_snapshot()
12089                            .chars_at(transpose_start)
12090                            .next()
12091                        {
12092                            edits.push((transpose_start..transpose_offset, String::new()));
12093                            edits.push((transpose_end..transpose_end, ch.to_string()));
12094                        }
12095                    }
12096                });
12097                edits
12098            });
12099            this.buffer
12100                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12101            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12102            this.change_selections(Default::default(), window, cx, |s| {
12103                s.select(selections);
12104            });
12105        });
12106    }
12107
12108    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12109        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12110        if self.mode.is_single_line() {
12111            cx.propagate();
12112            return;
12113        }
12114
12115        self.rewrap_impl(RewrapOptions::default(), cx)
12116    }
12117
12118    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12119        let buffer = self.buffer.read(cx).snapshot(cx);
12120        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12121
12122        #[derive(Clone, Debug, PartialEq)]
12123        enum CommentFormat {
12124            /// single line comment, with prefix for line
12125            Line(String),
12126            /// single line within a block comment, with prefix for line
12127            BlockLine(String),
12128            /// a single line of a block comment that includes the initial delimiter
12129            BlockCommentWithStart(BlockCommentConfig),
12130            /// a single line of a block comment that includes the ending delimiter
12131            BlockCommentWithEnd(BlockCommentConfig),
12132        }
12133
12134        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12135        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12136            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12137                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12138                .peekable();
12139
12140            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12141                row
12142            } else {
12143                return Vec::new();
12144            };
12145
12146            let language_settings = buffer.language_settings_at(selection.head(), cx);
12147            let language_scope = buffer.language_scope_at(selection.head());
12148
12149            let indent_and_prefix_for_row =
12150                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12151                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12152                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12153                        &language_scope
12154                    {
12155                        let indent_end = Point::new(row, indent.len);
12156                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12157                        let line_text_after_indent = buffer
12158                            .text_for_range(indent_end..line_end)
12159                            .collect::<String>();
12160
12161                        let is_within_comment_override = buffer
12162                            .language_scope_at(indent_end)
12163                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12164                        let comment_delimiters = if is_within_comment_override {
12165                            // we are within a comment syntax node, but we don't
12166                            // yet know what kind of comment: block, doc or line
12167                            match (
12168                                language_scope.documentation_comment(),
12169                                language_scope.block_comment(),
12170                            ) {
12171                                (Some(config), _) | (_, Some(config))
12172                                    if buffer.contains_str_at(indent_end, &config.start) =>
12173                                {
12174                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12175                                }
12176                                (Some(config), _) | (_, Some(config))
12177                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12178                                {
12179                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12180                                }
12181                                (Some(config), _) | (_, Some(config))
12182                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12183                                {
12184                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12185                                }
12186                                (_, _) => language_scope
12187                                    .line_comment_prefixes()
12188                                    .iter()
12189                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12190                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12191                            }
12192                        } else {
12193                            // we not in an overridden comment node, but we may
12194                            // be within a non-overridden line comment node
12195                            language_scope
12196                                .line_comment_prefixes()
12197                                .iter()
12198                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12199                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12200                        };
12201
12202                        let rewrap_prefix = language_scope
12203                            .rewrap_prefixes()
12204                            .iter()
12205                            .find_map(|prefix_regex| {
12206                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12207                                    if mat.start() == 0 {
12208                                        Some(mat.as_str().to_string())
12209                                    } else {
12210                                        None
12211                                    }
12212                                })
12213                            })
12214                            .flatten();
12215                        (comment_delimiters, rewrap_prefix)
12216                    } else {
12217                        (None, None)
12218                    };
12219                    (indent, comment_prefix, rewrap_prefix)
12220                };
12221
12222            let mut ranges = Vec::new();
12223            let from_empty_selection = selection.is_empty();
12224
12225            let mut current_range_start = first_row;
12226            let mut prev_row = first_row;
12227            let (
12228                mut current_range_indent,
12229                mut current_range_comment_delimiters,
12230                mut current_range_rewrap_prefix,
12231            ) = indent_and_prefix_for_row(first_row);
12232
12233            for row in non_blank_rows_iter.skip(1) {
12234                let has_paragraph_break = row > prev_row + 1;
12235
12236                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12237                    indent_and_prefix_for_row(row);
12238
12239                let has_indent_change = row_indent != current_range_indent;
12240                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12241
12242                let has_boundary_change = has_comment_change
12243                    || row_rewrap_prefix.is_some()
12244                    || (has_indent_change && current_range_comment_delimiters.is_some());
12245
12246                if has_paragraph_break || has_boundary_change {
12247                    ranges.push((
12248                        language_settings.clone(),
12249                        Point::new(current_range_start, 0)
12250                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12251                        current_range_indent,
12252                        current_range_comment_delimiters.clone(),
12253                        current_range_rewrap_prefix.clone(),
12254                        from_empty_selection,
12255                    ));
12256                    current_range_start = row;
12257                    current_range_indent = row_indent;
12258                    current_range_comment_delimiters = row_comment_delimiters;
12259                    current_range_rewrap_prefix = row_rewrap_prefix;
12260                }
12261                prev_row = row;
12262            }
12263
12264            ranges.push((
12265                language_settings.clone(),
12266                Point::new(current_range_start, 0)
12267                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12268                current_range_indent,
12269                current_range_comment_delimiters,
12270                current_range_rewrap_prefix,
12271                from_empty_selection,
12272            ));
12273
12274            ranges
12275        });
12276
12277        let mut edits = Vec::new();
12278        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12279
12280        for (
12281            language_settings,
12282            wrap_range,
12283            mut indent_size,
12284            comment_prefix,
12285            rewrap_prefix,
12286            from_empty_selection,
12287        ) in wrap_ranges
12288        {
12289            let mut start_row = wrap_range.start.row;
12290            let mut end_row = wrap_range.end.row;
12291
12292            // Skip selections that overlap with a range that has already been rewrapped.
12293            let selection_range = start_row..end_row;
12294            if rewrapped_row_ranges
12295                .iter()
12296                .any(|range| range.overlaps(&selection_range))
12297            {
12298                continue;
12299            }
12300
12301            let tab_size = language_settings.tab_size;
12302
12303            let (line_prefix, inside_comment) = match &comment_prefix {
12304                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12305                    (Some(prefix.as_str()), true)
12306                }
12307                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12308                    (Some(prefix.as_ref()), true)
12309                }
12310                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12311                    start: _,
12312                    end: _,
12313                    prefix,
12314                    tab_size,
12315                })) => {
12316                    indent_size.len += tab_size;
12317                    (Some(prefix.as_ref()), true)
12318                }
12319                None => (None, false),
12320            };
12321            let indent_prefix = indent_size.chars().collect::<String>();
12322            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12323
12324            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12325                RewrapBehavior::InComments => inside_comment,
12326                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12327                RewrapBehavior::Anywhere => true,
12328            };
12329
12330            let should_rewrap = options.override_language_settings
12331                || allow_rewrap_based_on_language
12332                || self.hard_wrap.is_some();
12333            if !should_rewrap {
12334                continue;
12335            }
12336
12337            if from_empty_selection {
12338                'expand_upwards: while start_row > 0 {
12339                    let prev_row = start_row - 1;
12340                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12341                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12342                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12343                    {
12344                        start_row = prev_row;
12345                    } else {
12346                        break 'expand_upwards;
12347                    }
12348                }
12349
12350                'expand_downwards: while end_row < buffer.max_point().row {
12351                    let next_row = end_row + 1;
12352                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12353                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12354                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12355                    {
12356                        end_row = next_row;
12357                    } else {
12358                        break 'expand_downwards;
12359                    }
12360                }
12361            }
12362
12363            let start = Point::new(start_row, 0);
12364            let start_offset = ToOffset::to_offset(&start, &buffer);
12365            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12366            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12367            let mut first_line_delimiter = None;
12368            let mut last_line_delimiter = None;
12369            let Some(lines_without_prefixes) = selection_text
12370                .lines()
12371                .enumerate()
12372                .map(|(ix, line)| {
12373                    let line_trimmed = line.trim_start();
12374                    if rewrap_prefix.is_some() && ix > 0 {
12375                        Ok(line_trimmed)
12376                    } else if let Some(
12377                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12378                            start,
12379                            prefix,
12380                            end,
12381                            tab_size,
12382                        })
12383                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12384                            start,
12385                            prefix,
12386                            end,
12387                            tab_size,
12388                        }),
12389                    ) = &comment_prefix
12390                    {
12391                        let line_trimmed = line_trimmed
12392                            .strip_prefix(start.as_ref())
12393                            .map(|s| {
12394                                let mut indent_size = indent_size;
12395                                indent_size.len -= tab_size;
12396                                let indent_prefix: String = indent_size.chars().collect();
12397                                first_line_delimiter = Some((indent_prefix, start));
12398                                s.trim_start()
12399                            })
12400                            .unwrap_or(line_trimmed);
12401                        let line_trimmed = line_trimmed
12402                            .strip_suffix(end.as_ref())
12403                            .map(|s| {
12404                                last_line_delimiter = Some(end);
12405                                s.trim_end()
12406                            })
12407                            .unwrap_or(line_trimmed);
12408                        let line_trimmed = line_trimmed
12409                            .strip_prefix(prefix.as_ref())
12410                            .unwrap_or(line_trimmed);
12411                        Ok(line_trimmed)
12412                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12413                        line_trimmed.strip_prefix(prefix).with_context(|| {
12414                            format!("line did not start with prefix {prefix:?}: {line:?}")
12415                        })
12416                    } else {
12417                        line_trimmed
12418                            .strip_prefix(&line_prefix.trim_start())
12419                            .with_context(|| {
12420                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12421                            })
12422                    }
12423                })
12424                .collect::<Result<Vec<_>, _>>()
12425                .log_err()
12426            else {
12427                continue;
12428            };
12429
12430            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12431                buffer
12432                    .language_settings_at(Point::new(start_row, 0), cx)
12433                    .preferred_line_length as usize
12434            });
12435
12436            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12437                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12438            } else {
12439                line_prefix.clone()
12440            };
12441
12442            let wrapped_text = {
12443                let mut wrapped_text = wrap_with_prefix(
12444                    line_prefix,
12445                    subsequent_lines_prefix,
12446                    lines_without_prefixes.join("\n"),
12447                    wrap_column,
12448                    tab_size,
12449                    options.preserve_existing_whitespace,
12450                );
12451
12452                if let Some((indent, delimiter)) = first_line_delimiter {
12453                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12454                }
12455                if let Some(last_line) = last_line_delimiter {
12456                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12457                }
12458
12459                wrapped_text
12460            };
12461
12462            // TODO: should always use char-based diff while still supporting cursor behavior that
12463            // matches vim.
12464            let mut diff_options = DiffOptions::default();
12465            if options.override_language_settings {
12466                diff_options.max_word_diff_len = 0;
12467                diff_options.max_word_diff_line_count = 0;
12468            } else {
12469                diff_options.max_word_diff_len = usize::MAX;
12470                diff_options.max_word_diff_line_count = usize::MAX;
12471            }
12472
12473            for (old_range, new_text) in
12474                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12475            {
12476                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12477                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12478                edits.push((edit_start..edit_end, new_text));
12479            }
12480
12481            rewrapped_row_ranges.push(start_row..=end_row);
12482        }
12483
12484        self.buffer
12485            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12486    }
12487
12488    pub fn cut_common(
12489        &mut self,
12490        cut_no_selection_line: bool,
12491        window: &mut Window,
12492        cx: &mut Context<Self>,
12493    ) -> ClipboardItem {
12494        let mut text = String::new();
12495        let buffer = self.buffer.read(cx).snapshot(cx);
12496        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12497        let mut clipboard_selections = Vec::with_capacity(selections.len());
12498        {
12499            let max_point = buffer.max_point();
12500            let mut is_first = true;
12501            for selection in &mut selections {
12502                let is_entire_line =
12503                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12504                if is_entire_line {
12505                    selection.start = Point::new(selection.start.row, 0);
12506                    if !selection.is_empty() && selection.end.column == 0 {
12507                        selection.end = cmp::min(max_point, selection.end);
12508                    } else {
12509                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12510                    }
12511                    selection.goal = SelectionGoal::None;
12512                }
12513                if is_first {
12514                    is_first = false;
12515                } else {
12516                    text += "\n";
12517                }
12518                let mut len = 0;
12519                for chunk in buffer.text_for_range(selection.start..selection.end) {
12520                    text.push_str(chunk);
12521                    len += chunk.len();
12522                }
12523                clipboard_selections.push(ClipboardSelection {
12524                    len,
12525                    is_entire_line,
12526                    first_line_indent: buffer
12527                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12528                        .len,
12529                });
12530            }
12531        }
12532
12533        self.transact(window, cx, |this, window, cx| {
12534            this.change_selections(Default::default(), window, cx, |s| {
12535                s.select(selections);
12536            });
12537            this.insert("", window, cx);
12538        });
12539        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12540    }
12541
12542    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12544        let item = self.cut_common(true, window, cx);
12545        cx.write_to_clipboard(item);
12546    }
12547
12548    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12550        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12551            s.move_with(|snapshot, sel| {
12552                if sel.is_empty() {
12553                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12554                }
12555                if sel.is_empty() {
12556                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12557                }
12558            });
12559        });
12560        let item = self.cut_common(false, window, cx);
12561        cx.set_global(KillRing(item))
12562    }
12563
12564    pub fn kill_ring_yank(
12565        &mut self,
12566        _: &KillRingYank,
12567        window: &mut Window,
12568        cx: &mut Context<Self>,
12569    ) {
12570        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12571        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12572            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12573                (kill_ring.text().to_string(), kill_ring.metadata_json())
12574            } else {
12575                return;
12576            }
12577        } else {
12578            return;
12579        };
12580        self.do_paste(&text, metadata, false, window, cx);
12581    }
12582
12583    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12584        self.do_copy(true, cx);
12585    }
12586
12587    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12588        self.do_copy(false, cx);
12589    }
12590
12591    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12592        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12593        let buffer = self.buffer.read(cx).read(cx);
12594        let mut text = String::new();
12595
12596        let mut clipboard_selections = Vec::with_capacity(selections.len());
12597        {
12598            let max_point = buffer.max_point();
12599            let mut is_first = true;
12600            for selection in &selections {
12601                let mut start = selection.start;
12602                let mut end = selection.end;
12603                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12604                let mut add_trailing_newline = false;
12605                if is_entire_line {
12606                    start = Point::new(start.row, 0);
12607                    let next_line_start = Point::new(end.row + 1, 0);
12608                    if next_line_start <= max_point {
12609                        end = next_line_start;
12610                    } else {
12611                        // We're on the last line without a trailing newline.
12612                        // Copy to the end of the line and add a newline afterwards.
12613                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12614                        add_trailing_newline = true;
12615                    }
12616                }
12617
12618                let mut trimmed_selections = Vec::new();
12619                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12620                    let row = MultiBufferRow(start.row);
12621                    let first_indent = buffer.indent_size_for_line(row);
12622                    if first_indent.len == 0 || start.column > first_indent.len {
12623                        trimmed_selections.push(start..end);
12624                    } else {
12625                        trimmed_selections.push(
12626                            Point::new(row.0, first_indent.len)
12627                                ..Point::new(row.0, buffer.line_len(row)),
12628                        );
12629                        for row in start.row + 1..=end.row {
12630                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12631                            if row == end.row {
12632                                line_len = end.column;
12633                            }
12634                            if line_len == 0 {
12635                                trimmed_selections
12636                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12637                                continue;
12638                            }
12639                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12640                            if row_indent_size.len >= first_indent.len {
12641                                trimmed_selections.push(
12642                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12643                                );
12644                            } else {
12645                                trimmed_selections.clear();
12646                                trimmed_selections.push(start..end);
12647                                break;
12648                            }
12649                        }
12650                    }
12651                } else {
12652                    trimmed_selections.push(start..end);
12653                }
12654
12655                for trimmed_range in trimmed_selections {
12656                    if is_first {
12657                        is_first = false;
12658                    } else {
12659                        text += "\n";
12660                    }
12661                    let mut len = 0;
12662                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12663                        text.push_str(chunk);
12664                        len += chunk.len();
12665                    }
12666                    if add_trailing_newline {
12667                        text.push('\n');
12668                        len += 1;
12669                    }
12670                    clipboard_selections.push(ClipboardSelection {
12671                        len,
12672                        is_entire_line,
12673                        first_line_indent: buffer
12674                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12675                            .len,
12676                    });
12677                }
12678            }
12679        }
12680
12681        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12682            text,
12683            clipboard_selections,
12684        ));
12685    }
12686
12687    pub fn do_paste(
12688        &mut self,
12689        text: &String,
12690        clipboard_selections: Option<Vec<ClipboardSelection>>,
12691        handle_entire_lines: bool,
12692        window: &mut Window,
12693        cx: &mut Context<Self>,
12694    ) {
12695        if self.read_only(cx) {
12696            return;
12697        }
12698
12699        let clipboard_text = Cow::Borrowed(text.as_str());
12700
12701        self.transact(window, cx, |this, window, cx| {
12702            let had_active_edit_prediction = this.has_active_edit_prediction();
12703            let display_map = this.display_snapshot(cx);
12704            let old_selections = this.selections.all::<usize>(&display_map);
12705            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12706
12707            if let Some(mut clipboard_selections) = clipboard_selections {
12708                let all_selections_were_entire_line =
12709                    clipboard_selections.iter().all(|s| s.is_entire_line);
12710                let first_selection_indent_column =
12711                    clipboard_selections.first().map(|s| s.first_line_indent);
12712                if clipboard_selections.len() != old_selections.len() {
12713                    clipboard_selections.drain(..);
12714                }
12715                let mut auto_indent_on_paste = true;
12716
12717                this.buffer.update(cx, |buffer, cx| {
12718                    let snapshot = buffer.read(cx);
12719                    auto_indent_on_paste = snapshot
12720                        .language_settings_at(cursor_offset, cx)
12721                        .auto_indent_on_paste;
12722
12723                    let mut start_offset = 0;
12724                    let mut edits = Vec::new();
12725                    let mut original_indent_columns = Vec::new();
12726                    for (ix, selection) in old_selections.iter().enumerate() {
12727                        let to_insert;
12728                        let entire_line;
12729                        let original_indent_column;
12730                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12731                            let end_offset = start_offset + clipboard_selection.len;
12732                            to_insert = &clipboard_text[start_offset..end_offset];
12733                            entire_line = clipboard_selection.is_entire_line;
12734                            start_offset = end_offset + 1;
12735                            original_indent_column = Some(clipboard_selection.first_line_indent);
12736                        } else {
12737                            to_insert = &*clipboard_text;
12738                            entire_line = all_selections_were_entire_line;
12739                            original_indent_column = first_selection_indent_column
12740                        }
12741
12742                        let (range, to_insert) =
12743                            if selection.is_empty() && handle_entire_lines && entire_line {
12744                                // If the corresponding selection was empty when this slice of the
12745                                // clipboard text was written, then the entire line containing the
12746                                // selection was copied. If this selection is also currently empty,
12747                                // then paste the line before the current line of the buffer.
12748                                let column = selection.start.to_point(&snapshot).column as usize;
12749                                let line_start = selection.start - column;
12750                                (line_start..line_start, Cow::Borrowed(to_insert))
12751                            } else {
12752                                let language = snapshot.language_at(selection.head());
12753                                let range = selection.range();
12754                                if let Some(language) = language
12755                                    && language.name() == "Markdown".into()
12756                                {
12757                                    edit_for_markdown_paste(
12758                                        &snapshot,
12759                                        range,
12760                                        to_insert,
12761                                        url::Url::parse(to_insert).ok(),
12762                                    )
12763                                } else {
12764                                    (range, Cow::Borrowed(to_insert))
12765                                }
12766                            };
12767
12768                        edits.push((range, to_insert));
12769                        original_indent_columns.push(original_indent_column);
12770                    }
12771                    drop(snapshot);
12772
12773                    buffer.edit(
12774                        edits,
12775                        if auto_indent_on_paste {
12776                            Some(AutoindentMode::Block {
12777                                original_indent_columns,
12778                            })
12779                        } else {
12780                            None
12781                        },
12782                        cx,
12783                    );
12784                });
12785
12786                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12787                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12788            } else {
12789                let url = url::Url::parse(&clipboard_text).ok();
12790
12791                let auto_indent_mode = if !clipboard_text.is_empty() {
12792                    Some(AutoindentMode::Block {
12793                        original_indent_columns: Vec::new(),
12794                    })
12795                } else {
12796                    None
12797                };
12798
12799                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12800                    let snapshot = buffer.snapshot(cx);
12801
12802                    let anchors = old_selections
12803                        .iter()
12804                        .map(|s| {
12805                            let anchor = snapshot.anchor_after(s.head());
12806                            s.map(|_| anchor)
12807                        })
12808                        .collect::<Vec<_>>();
12809
12810                    let mut edits = Vec::new();
12811
12812                    for selection in old_selections.iter() {
12813                        let language = snapshot.language_at(selection.head());
12814                        let range = selection.range();
12815
12816                        let (edit_range, edit_text) = if let Some(language) = language
12817                            && language.name() == "Markdown".into()
12818                        {
12819                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12820                        } else {
12821                            (range, clipboard_text.clone())
12822                        };
12823
12824                        edits.push((edit_range, edit_text));
12825                    }
12826
12827                    drop(snapshot);
12828                    buffer.edit(edits, auto_indent_mode, cx);
12829
12830                    anchors
12831                });
12832
12833                this.change_selections(Default::default(), window, cx, |s| {
12834                    s.select_anchors(selection_anchors);
12835                });
12836            }
12837
12838            let trigger_in_words =
12839                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12840
12841            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12842        });
12843    }
12844
12845    pub fn diff_clipboard_with_selection(
12846        &mut self,
12847        _: &DiffClipboardWithSelection,
12848        window: &mut Window,
12849        cx: &mut Context<Self>,
12850    ) {
12851        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12852
12853        if selections.is_empty() {
12854            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12855            return;
12856        };
12857
12858        let clipboard_text = match cx.read_from_clipboard() {
12859            Some(item) => match item.entries().first() {
12860                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12861                _ => None,
12862            },
12863            None => None,
12864        };
12865
12866        let Some(clipboard_text) = clipboard_text else {
12867            log::warn!("Clipboard doesn't contain text.");
12868            return;
12869        };
12870
12871        window.dispatch_action(
12872            Box::new(DiffClipboardWithSelectionData {
12873                clipboard_text,
12874                editor: cx.entity(),
12875            }),
12876            cx,
12877        );
12878    }
12879
12880    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12881        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12882        if let Some(item) = cx.read_from_clipboard() {
12883            let entries = item.entries();
12884
12885            match entries.first() {
12886                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12887                // of all the pasted entries.
12888                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12889                    .do_paste(
12890                        clipboard_string.text(),
12891                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12892                        true,
12893                        window,
12894                        cx,
12895                    ),
12896                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12897            }
12898        }
12899    }
12900
12901    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12902        if self.read_only(cx) {
12903            return;
12904        }
12905
12906        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12907
12908        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12909            if let Some((selections, _)) =
12910                self.selection_history.transaction(transaction_id).cloned()
12911            {
12912                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12913                    s.select_anchors(selections.to_vec());
12914                });
12915            } else {
12916                log::error!(
12917                    "No entry in selection_history found for undo. \
12918                     This may correspond to a bug where undo does not update the selection. \
12919                     If this is occurring, please add details to \
12920                     https://github.com/zed-industries/zed/issues/22692"
12921                );
12922            }
12923            self.request_autoscroll(Autoscroll::fit(), cx);
12924            self.unmark_text(window, cx);
12925            self.refresh_edit_prediction(true, false, window, cx);
12926            cx.emit(EditorEvent::Edited { transaction_id });
12927            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12928        }
12929    }
12930
12931    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12932        if self.read_only(cx) {
12933            return;
12934        }
12935
12936        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12937
12938        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12939            if let Some((_, Some(selections))) =
12940                self.selection_history.transaction(transaction_id).cloned()
12941            {
12942                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12943                    s.select_anchors(selections.to_vec());
12944                });
12945            } else {
12946                log::error!(
12947                    "No entry in selection_history found for redo. \
12948                     This may correspond to a bug where undo does not update the selection. \
12949                     If this is occurring, please add details to \
12950                     https://github.com/zed-industries/zed/issues/22692"
12951                );
12952            }
12953            self.request_autoscroll(Autoscroll::fit(), cx);
12954            self.unmark_text(window, cx);
12955            self.refresh_edit_prediction(true, false, window, cx);
12956            cx.emit(EditorEvent::Edited { transaction_id });
12957        }
12958    }
12959
12960    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12961        self.buffer
12962            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12963    }
12964
12965    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12966        self.buffer
12967            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12968    }
12969
12970    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12971        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12972        self.change_selections(Default::default(), window, cx, |s| {
12973            s.move_with(|map, selection| {
12974                let cursor = if selection.is_empty() {
12975                    movement::left(map, selection.start)
12976                } else {
12977                    selection.start
12978                };
12979                selection.collapse_to(cursor, SelectionGoal::None);
12980            });
12981        })
12982    }
12983
12984    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12986        self.change_selections(Default::default(), window, cx, |s| {
12987            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12988        })
12989    }
12990
12991    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12993        self.change_selections(Default::default(), window, cx, |s| {
12994            s.move_with(|map, selection| {
12995                let cursor = if selection.is_empty() {
12996                    movement::right(map, selection.end)
12997                } else {
12998                    selection.end
12999                };
13000                selection.collapse_to(cursor, SelectionGoal::None)
13001            });
13002        })
13003    }
13004
13005    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13007        self.change_selections(Default::default(), window, cx, |s| {
13008            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13009        });
13010    }
13011
13012    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13013        if self.take_rename(true, window, cx).is_some() {
13014            return;
13015        }
13016
13017        if self.mode.is_single_line() {
13018            cx.propagate();
13019            return;
13020        }
13021
13022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13023
13024        let text_layout_details = &self.text_layout_details(window);
13025        let selection_count = self.selections.count();
13026        let first_selection = self.selections.first_anchor();
13027
13028        self.change_selections(Default::default(), window, cx, |s| {
13029            s.move_with(|map, selection| {
13030                if !selection.is_empty() {
13031                    selection.goal = SelectionGoal::None;
13032                }
13033                let (cursor, goal) = movement::up(
13034                    map,
13035                    selection.start,
13036                    selection.goal,
13037                    false,
13038                    text_layout_details,
13039                );
13040                selection.collapse_to(cursor, goal);
13041            });
13042        });
13043
13044        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13045        {
13046            cx.propagate();
13047        }
13048    }
13049
13050    pub fn move_up_by_lines(
13051        &mut self,
13052        action: &MoveUpByLines,
13053        window: &mut Window,
13054        cx: &mut Context<Self>,
13055    ) {
13056        if self.take_rename(true, window, cx).is_some() {
13057            return;
13058        }
13059
13060        if self.mode.is_single_line() {
13061            cx.propagate();
13062            return;
13063        }
13064
13065        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13066
13067        let text_layout_details = &self.text_layout_details(window);
13068
13069        self.change_selections(Default::default(), window, cx, |s| {
13070            s.move_with(|map, selection| {
13071                if !selection.is_empty() {
13072                    selection.goal = SelectionGoal::None;
13073                }
13074                let (cursor, goal) = movement::up_by_rows(
13075                    map,
13076                    selection.start,
13077                    action.lines,
13078                    selection.goal,
13079                    false,
13080                    text_layout_details,
13081                );
13082                selection.collapse_to(cursor, goal);
13083            });
13084        })
13085    }
13086
13087    pub fn move_down_by_lines(
13088        &mut self,
13089        action: &MoveDownByLines,
13090        window: &mut Window,
13091        cx: &mut Context<Self>,
13092    ) {
13093        if self.take_rename(true, window, cx).is_some() {
13094            return;
13095        }
13096
13097        if self.mode.is_single_line() {
13098            cx.propagate();
13099            return;
13100        }
13101
13102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13103
13104        let text_layout_details = &self.text_layout_details(window);
13105
13106        self.change_selections(Default::default(), window, cx, |s| {
13107            s.move_with(|map, selection| {
13108                if !selection.is_empty() {
13109                    selection.goal = SelectionGoal::None;
13110                }
13111                let (cursor, goal) = movement::down_by_rows(
13112                    map,
13113                    selection.start,
13114                    action.lines,
13115                    selection.goal,
13116                    false,
13117                    text_layout_details,
13118                );
13119                selection.collapse_to(cursor, goal);
13120            });
13121        })
13122    }
13123
13124    pub fn select_down_by_lines(
13125        &mut self,
13126        action: &SelectDownByLines,
13127        window: &mut Window,
13128        cx: &mut Context<Self>,
13129    ) {
13130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13131        let text_layout_details = &self.text_layout_details(window);
13132        self.change_selections(Default::default(), window, cx, |s| {
13133            s.move_heads_with(|map, head, goal| {
13134                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13135            })
13136        })
13137    }
13138
13139    pub fn select_up_by_lines(
13140        &mut self,
13141        action: &SelectUpByLines,
13142        window: &mut Window,
13143        cx: &mut Context<Self>,
13144    ) {
13145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13146        let text_layout_details = &self.text_layout_details(window);
13147        self.change_selections(Default::default(), window, cx, |s| {
13148            s.move_heads_with(|map, head, goal| {
13149                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13150            })
13151        })
13152    }
13153
13154    pub fn select_page_up(
13155        &mut self,
13156        _: &SelectPageUp,
13157        window: &mut Window,
13158        cx: &mut Context<Self>,
13159    ) {
13160        let Some(row_count) = self.visible_row_count() else {
13161            return;
13162        };
13163
13164        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13165
13166        let text_layout_details = &self.text_layout_details(window);
13167
13168        self.change_selections(Default::default(), window, cx, |s| {
13169            s.move_heads_with(|map, head, goal| {
13170                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13171            })
13172        })
13173    }
13174
13175    pub fn move_page_up(
13176        &mut self,
13177        action: &MovePageUp,
13178        window: &mut Window,
13179        cx: &mut Context<Self>,
13180    ) {
13181        if self.take_rename(true, window, cx).is_some() {
13182            return;
13183        }
13184
13185        if self
13186            .context_menu
13187            .borrow_mut()
13188            .as_mut()
13189            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13190            .unwrap_or(false)
13191        {
13192            return;
13193        }
13194
13195        if matches!(self.mode, EditorMode::SingleLine) {
13196            cx.propagate();
13197            return;
13198        }
13199
13200        let Some(row_count) = self.visible_row_count() else {
13201            return;
13202        };
13203
13204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13205
13206        let effects = if action.center_cursor {
13207            SelectionEffects::scroll(Autoscroll::center())
13208        } else {
13209            SelectionEffects::default()
13210        };
13211
13212        let text_layout_details = &self.text_layout_details(window);
13213
13214        self.change_selections(effects, window, cx, |s| {
13215            s.move_with(|map, selection| {
13216                if !selection.is_empty() {
13217                    selection.goal = SelectionGoal::None;
13218                }
13219                let (cursor, goal) = movement::up_by_rows(
13220                    map,
13221                    selection.end,
13222                    row_count,
13223                    selection.goal,
13224                    false,
13225                    text_layout_details,
13226                );
13227                selection.collapse_to(cursor, goal);
13228            });
13229        });
13230    }
13231
13232    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13233        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13234        let text_layout_details = &self.text_layout_details(window);
13235        self.change_selections(Default::default(), window, cx, |s| {
13236            s.move_heads_with(|map, head, goal| {
13237                movement::up(map, head, goal, false, text_layout_details)
13238            })
13239        })
13240    }
13241
13242    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13243        self.take_rename(true, window, cx);
13244
13245        if self.mode.is_single_line() {
13246            cx.propagate();
13247            return;
13248        }
13249
13250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13251
13252        let text_layout_details = &self.text_layout_details(window);
13253        let selection_count = self.selections.count();
13254        let first_selection = self.selections.first_anchor();
13255
13256        self.change_selections(Default::default(), window, cx, |s| {
13257            s.move_with(|map, selection| {
13258                if !selection.is_empty() {
13259                    selection.goal = SelectionGoal::None;
13260                }
13261                let (cursor, goal) = movement::down(
13262                    map,
13263                    selection.end,
13264                    selection.goal,
13265                    false,
13266                    text_layout_details,
13267                );
13268                selection.collapse_to(cursor, goal);
13269            });
13270        });
13271
13272        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13273        {
13274            cx.propagate();
13275        }
13276    }
13277
13278    pub fn select_page_down(
13279        &mut self,
13280        _: &SelectPageDown,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        let Some(row_count) = self.visible_row_count() else {
13285            return;
13286        };
13287
13288        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13289
13290        let text_layout_details = &self.text_layout_details(window);
13291
13292        self.change_selections(Default::default(), window, cx, |s| {
13293            s.move_heads_with(|map, head, goal| {
13294                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13295            })
13296        })
13297    }
13298
13299    pub fn move_page_down(
13300        &mut self,
13301        action: &MovePageDown,
13302        window: &mut Window,
13303        cx: &mut Context<Self>,
13304    ) {
13305        if self.take_rename(true, window, cx).is_some() {
13306            return;
13307        }
13308
13309        if self
13310            .context_menu
13311            .borrow_mut()
13312            .as_mut()
13313            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13314            .unwrap_or(false)
13315        {
13316            return;
13317        }
13318
13319        if matches!(self.mode, EditorMode::SingleLine) {
13320            cx.propagate();
13321            return;
13322        }
13323
13324        let Some(row_count) = self.visible_row_count() else {
13325            return;
13326        };
13327
13328        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13329
13330        let effects = if action.center_cursor {
13331            SelectionEffects::scroll(Autoscroll::center())
13332        } else {
13333            SelectionEffects::default()
13334        };
13335
13336        let text_layout_details = &self.text_layout_details(window);
13337        self.change_selections(effects, window, cx, |s| {
13338            s.move_with(|map, selection| {
13339                if !selection.is_empty() {
13340                    selection.goal = SelectionGoal::None;
13341                }
13342                let (cursor, goal) = movement::down_by_rows(
13343                    map,
13344                    selection.end,
13345                    row_count,
13346                    selection.goal,
13347                    false,
13348                    text_layout_details,
13349                );
13350                selection.collapse_to(cursor, goal);
13351            });
13352        });
13353    }
13354
13355    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13357        let text_layout_details = &self.text_layout_details(window);
13358        self.change_selections(Default::default(), window, cx, |s| {
13359            s.move_heads_with(|map, head, goal| {
13360                movement::down(map, head, goal, false, text_layout_details)
13361            })
13362        });
13363    }
13364
13365    pub fn context_menu_first(
13366        &mut self,
13367        _: &ContextMenuFirst,
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_first(self.completion_provider.as_deref(), window, cx);
13373        }
13374    }
13375
13376    pub fn context_menu_prev(
13377        &mut self,
13378        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), window, cx);
13384        }
13385    }
13386
13387    pub fn context_menu_next(
13388        &mut self,
13389        _: &ContextMenuNext,
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_next(self.completion_provider.as_deref(), window, cx);
13395        }
13396    }
13397
13398    pub fn context_menu_last(
13399        &mut self,
13400        _: &ContextMenuLast,
13401        window: &mut Window,
13402        cx: &mut Context<Self>,
13403    ) {
13404        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13405            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13406        }
13407    }
13408
13409    pub fn signature_help_prev(
13410        &mut self,
13411        _: &SignatureHelpPrevious,
13412        _: &mut Window,
13413        cx: &mut Context<Self>,
13414    ) {
13415        if let Some(popover) = self.signature_help_state.popover_mut() {
13416            if popover.current_signature == 0 {
13417                popover.current_signature = popover.signatures.len() - 1;
13418            } else {
13419                popover.current_signature -= 1;
13420            }
13421            cx.notify();
13422        }
13423    }
13424
13425    pub fn signature_help_next(
13426        &mut self,
13427        _: &SignatureHelpNext,
13428        _: &mut Window,
13429        cx: &mut Context<Self>,
13430    ) {
13431        if let Some(popover) = self.signature_help_state.popover_mut() {
13432            if popover.current_signature + 1 == popover.signatures.len() {
13433                popover.current_signature = 0;
13434            } else {
13435                popover.current_signature += 1;
13436            }
13437            cx.notify();
13438        }
13439    }
13440
13441    pub fn move_to_previous_word_start(
13442        &mut self,
13443        _: &MoveToPreviousWordStart,
13444        window: &mut Window,
13445        cx: &mut Context<Self>,
13446    ) {
13447        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13448        self.change_selections(Default::default(), window, cx, |s| {
13449            s.move_cursors_with(|map, head, _| {
13450                (
13451                    movement::previous_word_start(map, head),
13452                    SelectionGoal::None,
13453                )
13454            });
13455        })
13456    }
13457
13458    pub fn move_to_previous_subword_start(
13459        &mut self,
13460        _: &MoveToPreviousSubwordStart,
13461        window: &mut Window,
13462        cx: &mut Context<Self>,
13463    ) {
13464        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13465        self.change_selections(Default::default(), window, cx, |s| {
13466            s.move_cursors_with(|map, head, _| {
13467                (
13468                    movement::previous_subword_start(map, head),
13469                    SelectionGoal::None,
13470                )
13471            });
13472        })
13473    }
13474
13475    pub fn select_to_previous_word_start(
13476        &mut self,
13477        _: &SelectToPreviousWordStart,
13478        window: &mut Window,
13479        cx: &mut Context<Self>,
13480    ) {
13481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13482        self.change_selections(Default::default(), window, cx, |s| {
13483            s.move_heads_with(|map, head, _| {
13484                (
13485                    movement::previous_word_start(map, head),
13486                    SelectionGoal::None,
13487                )
13488            });
13489        })
13490    }
13491
13492    pub fn select_to_previous_subword_start(
13493        &mut self,
13494        _: &SelectToPreviousSubwordStart,
13495        window: &mut Window,
13496        cx: &mut Context<Self>,
13497    ) {
13498        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13499        self.change_selections(Default::default(), window, cx, |s| {
13500            s.move_heads_with(|map, head, _| {
13501                (
13502                    movement::previous_subword_start(map, head),
13503                    SelectionGoal::None,
13504                )
13505            });
13506        })
13507    }
13508
13509    pub fn delete_to_previous_word_start(
13510        &mut self,
13511        action: &DeleteToPreviousWordStart,
13512        window: &mut Window,
13513        cx: &mut Context<Self>,
13514    ) {
13515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13516        self.transact(window, cx, |this, window, cx| {
13517            this.select_autoclose_pair(window, cx);
13518            this.change_selections(Default::default(), window, cx, |s| {
13519                s.move_with(|map, selection| {
13520                    if selection.is_empty() {
13521                        let mut cursor = if action.ignore_newlines {
13522                            movement::previous_word_start(map, selection.head())
13523                        } else {
13524                            movement::previous_word_start_or_newline(map, selection.head())
13525                        };
13526                        cursor = movement::adjust_greedy_deletion(
13527                            map,
13528                            selection.head(),
13529                            cursor,
13530                            action.ignore_brackets,
13531                        );
13532                        selection.set_head(cursor, SelectionGoal::None);
13533                    }
13534                });
13535            });
13536            this.insert("", window, cx);
13537        });
13538    }
13539
13540    pub fn delete_to_previous_subword_start(
13541        &mut self,
13542        _: &DeleteToPreviousSubwordStart,
13543        window: &mut Window,
13544        cx: &mut Context<Self>,
13545    ) {
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13547        self.transact(window, cx, |this, window, cx| {
13548            this.select_autoclose_pair(window, cx);
13549            this.change_selections(Default::default(), window, cx, |s| {
13550                s.move_with(|map, selection| {
13551                    if selection.is_empty() {
13552                        let mut cursor = movement::previous_subword_start(map, selection.head());
13553                        cursor =
13554                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13555                        selection.set_head(cursor, SelectionGoal::None);
13556                    }
13557                });
13558            });
13559            this.insert("", window, cx);
13560        });
13561    }
13562
13563    pub fn move_to_next_word_end(
13564        &mut self,
13565        _: &MoveToNextWordEnd,
13566        window: &mut Window,
13567        cx: &mut Context<Self>,
13568    ) {
13569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13570        self.change_selections(Default::default(), window, cx, |s| {
13571            s.move_cursors_with(|map, head, _| {
13572                (movement::next_word_end(map, head), SelectionGoal::None)
13573            });
13574        })
13575    }
13576
13577    pub fn move_to_next_subword_end(
13578        &mut self,
13579        _: &MoveToNextSubwordEnd,
13580        window: &mut Window,
13581        cx: &mut Context<Self>,
13582    ) {
13583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13584        self.change_selections(Default::default(), window, cx, |s| {
13585            s.move_cursors_with(|map, head, _| {
13586                (movement::next_subword_end(map, head), SelectionGoal::None)
13587            });
13588        })
13589    }
13590
13591    pub fn select_to_next_word_end(
13592        &mut self,
13593        _: &SelectToNextWordEnd,
13594        window: &mut Window,
13595        cx: &mut Context<Self>,
13596    ) {
13597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13598        self.change_selections(Default::default(), window, cx, |s| {
13599            s.move_heads_with(|map, head, _| {
13600                (movement::next_word_end(map, head), SelectionGoal::None)
13601            });
13602        })
13603    }
13604
13605    pub fn select_to_next_subword_end(
13606        &mut self,
13607        _: &SelectToNextSubwordEnd,
13608        window: &mut Window,
13609        cx: &mut Context<Self>,
13610    ) {
13611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13612        self.change_selections(Default::default(), window, cx, |s| {
13613            s.move_heads_with(|map, head, _| {
13614                (movement::next_subword_end(map, head), SelectionGoal::None)
13615            });
13616        })
13617    }
13618
13619    pub fn delete_to_next_word_end(
13620        &mut self,
13621        action: &DeleteToNextWordEnd,
13622        window: &mut Window,
13623        cx: &mut Context<Self>,
13624    ) {
13625        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13626        self.transact(window, cx, |this, window, cx| {
13627            this.change_selections(Default::default(), window, cx, |s| {
13628                s.move_with(|map, selection| {
13629                    if selection.is_empty() {
13630                        let mut cursor = if action.ignore_newlines {
13631                            movement::next_word_end(map, selection.head())
13632                        } else {
13633                            movement::next_word_end_or_newline(map, selection.head())
13634                        };
13635                        cursor = movement::adjust_greedy_deletion(
13636                            map,
13637                            selection.head(),
13638                            cursor,
13639                            action.ignore_brackets,
13640                        );
13641                        selection.set_head(cursor, SelectionGoal::None);
13642                    }
13643                });
13644            });
13645            this.insert("", window, cx);
13646        });
13647    }
13648
13649    pub fn delete_to_next_subword_end(
13650        &mut self,
13651        _: &DeleteToNextSubwordEnd,
13652        window: &mut Window,
13653        cx: &mut Context<Self>,
13654    ) {
13655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13656        self.transact(window, cx, |this, window, cx| {
13657            this.change_selections(Default::default(), window, cx, |s| {
13658                s.move_with(|map, selection| {
13659                    if selection.is_empty() {
13660                        let mut cursor = movement::next_subword_end(map, selection.head());
13661                        cursor =
13662                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13663                        selection.set_head(cursor, SelectionGoal::None);
13664                    }
13665                });
13666            });
13667            this.insert("", window, cx);
13668        });
13669    }
13670
13671    pub fn move_to_beginning_of_line(
13672        &mut self,
13673        action: &MoveToBeginningOfLine,
13674        window: &mut Window,
13675        cx: &mut Context<Self>,
13676    ) {
13677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13678        self.change_selections(Default::default(), window, cx, |s| {
13679            s.move_cursors_with(|map, head, _| {
13680                (
13681                    movement::indented_line_beginning(
13682                        map,
13683                        head,
13684                        action.stop_at_soft_wraps,
13685                        action.stop_at_indent,
13686                    ),
13687                    SelectionGoal::None,
13688                )
13689            });
13690        })
13691    }
13692
13693    pub fn select_to_beginning_of_line(
13694        &mut self,
13695        action: &SelectToBeginningOfLine,
13696        window: &mut Window,
13697        cx: &mut Context<Self>,
13698    ) {
13699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13700        self.change_selections(Default::default(), window, cx, |s| {
13701            s.move_heads_with(|map, head, _| {
13702                (
13703                    movement::indented_line_beginning(
13704                        map,
13705                        head,
13706                        action.stop_at_soft_wraps,
13707                        action.stop_at_indent,
13708                    ),
13709                    SelectionGoal::None,
13710                )
13711            });
13712        });
13713    }
13714
13715    pub fn delete_to_beginning_of_line(
13716        &mut self,
13717        action: &DeleteToBeginningOfLine,
13718        window: &mut Window,
13719        cx: &mut Context<Self>,
13720    ) {
13721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13722        self.transact(window, cx, |this, window, cx| {
13723            this.change_selections(Default::default(), window, cx, |s| {
13724                s.move_with(|_, selection| {
13725                    selection.reversed = true;
13726                });
13727            });
13728
13729            this.select_to_beginning_of_line(
13730                &SelectToBeginningOfLine {
13731                    stop_at_soft_wraps: false,
13732                    stop_at_indent: action.stop_at_indent,
13733                },
13734                window,
13735                cx,
13736            );
13737            this.backspace(&Backspace, window, cx);
13738        });
13739    }
13740
13741    pub fn move_to_end_of_line(
13742        &mut self,
13743        action: &MoveToEndOfLine,
13744        window: &mut Window,
13745        cx: &mut Context<Self>,
13746    ) {
13747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13748        self.change_selections(Default::default(), window, cx, |s| {
13749            s.move_cursors_with(|map, head, _| {
13750                (
13751                    movement::line_end(map, head, action.stop_at_soft_wraps),
13752                    SelectionGoal::None,
13753                )
13754            });
13755        })
13756    }
13757
13758    pub fn select_to_end_of_line(
13759        &mut self,
13760        action: &SelectToEndOfLine,
13761        window: &mut Window,
13762        cx: &mut Context<Self>,
13763    ) {
13764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13765        self.change_selections(Default::default(), window, cx, |s| {
13766            s.move_heads_with(|map, head, _| {
13767                (
13768                    movement::line_end(map, head, action.stop_at_soft_wraps),
13769                    SelectionGoal::None,
13770                )
13771            });
13772        })
13773    }
13774
13775    pub fn delete_to_end_of_line(
13776        &mut self,
13777        _: &DeleteToEndOfLine,
13778        window: &mut Window,
13779        cx: &mut Context<Self>,
13780    ) {
13781        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13782        self.transact(window, cx, |this, window, cx| {
13783            this.select_to_end_of_line(
13784                &SelectToEndOfLine {
13785                    stop_at_soft_wraps: false,
13786                },
13787                window,
13788                cx,
13789            );
13790            this.delete(&Delete, window, cx);
13791        });
13792    }
13793
13794    pub fn cut_to_end_of_line(
13795        &mut self,
13796        action: &CutToEndOfLine,
13797        window: &mut Window,
13798        cx: &mut Context<Self>,
13799    ) {
13800        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13801        self.transact(window, cx, |this, window, cx| {
13802            this.select_to_end_of_line(
13803                &SelectToEndOfLine {
13804                    stop_at_soft_wraps: false,
13805                },
13806                window,
13807                cx,
13808            );
13809            if !action.stop_at_newlines {
13810                this.change_selections(Default::default(), window, cx, |s| {
13811                    s.move_with(|_, sel| {
13812                        if sel.is_empty() {
13813                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13814                        }
13815                    });
13816                });
13817            }
13818            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13819            let item = this.cut_common(false, window, cx);
13820            cx.write_to_clipboard(item);
13821        });
13822    }
13823
13824    pub fn move_to_start_of_paragraph(
13825        &mut self,
13826        _: &MoveToStartOfParagraph,
13827        window: &mut Window,
13828        cx: &mut Context<Self>,
13829    ) {
13830        if matches!(self.mode, EditorMode::SingleLine) {
13831            cx.propagate();
13832            return;
13833        }
13834        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13835        self.change_selections(Default::default(), window, cx, |s| {
13836            s.move_with(|map, selection| {
13837                selection.collapse_to(
13838                    movement::start_of_paragraph(map, selection.head(), 1),
13839                    SelectionGoal::None,
13840                )
13841            });
13842        })
13843    }
13844
13845    pub fn move_to_end_of_paragraph(
13846        &mut self,
13847        _: &MoveToEndOfParagraph,
13848        window: &mut Window,
13849        cx: &mut Context<Self>,
13850    ) {
13851        if matches!(self.mode, EditorMode::SingleLine) {
13852            cx.propagate();
13853            return;
13854        }
13855        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13856        self.change_selections(Default::default(), window, cx, |s| {
13857            s.move_with(|map, selection| {
13858                selection.collapse_to(
13859                    movement::end_of_paragraph(map, selection.head(), 1),
13860                    SelectionGoal::None,
13861                )
13862            });
13863        })
13864    }
13865
13866    pub fn select_to_start_of_paragraph(
13867        &mut self,
13868        _: &SelectToStartOfParagraph,
13869        window: &mut Window,
13870        cx: &mut Context<Self>,
13871    ) {
13872        if matches!(self.mode, EditorMode::SingleLine) {
13873            cx.propagate();
13874            return;
13875        }
13876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13877        self.change_selections(Default::default(), window, cx, |s| {
13878            s.move_heads_with(|map, head, _| {
13879                (
13880                    movement::start_of_paragraph(map, head, 1),
13881                    SelectionGoal::None,
13882                )
13883            });
13884        })
13885    }
13886
13887    pub fn select_to_end_of_paragraph(
13888        &mut self,
13889        _: &SelectToEndOfParagraph,
13890        window: &mut Window,
13891        cx: &mut Context<Self>,
13892    ) {
13893        if matches!(self.mode, EditorMode::SingleLine) {
13894            cx.propagate();
13895            return;
13896        }
13897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13898        self.change_selections(Default::default(), window, cx, |s| {
13899            s.move_heads_with(|map, head, _| {
13900                (
13901                    movement::end_of_paragraph(map, head, 1),
13902                    SelectionGoal::None,
13903                )
13904            });
13905        })
13906    }
13907
13908    pub fn move_to_start_of_excerpt(
13909        &mut self,
13910        _: &MoveToStartOfExcerpt,
13911        window: &mut Window,
13912        cx: &mut Context<Self>,
13913    ) {
13914        if matches!(self.mode, EditorMode::SingleLine) {
13915            cx.propagate();
13916            return;
13917        }
13918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13919        self.change_selections(Default::default(), window, cx, |s| {
13920            s.move_with(|map, selection| {
13921                selection.collapse_to(
13922                    movement::start_of_excerpt(
13923                        map,
13924                        selection.head(),
13925                        workspace::searchable::Direction::Prev,
13926                    ),
13927                    SelectionGoal::None,
13928                )
13929            });
13930        })
13931    }
13932
13933    pub fn move_to_start_of_next_excerpt(
13934        &mut self,
13935        _: &MoveToStartOfNextExcerpt,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) {
13939        if matches!(self.mode, EditorMode::SingleLine) {
13940            cx.propagate();
13941            return;
13942        }
13943
13944        self.change_selections(Default::default(), window, cx, |s| {
13945            s.move_with(|map, selection| {
13946                selection.collapse_to(
13947                    movement::start_of_excerpt(
13948                        map,
13949                        selection.head(),
13950                        workspace::searchable::Direction::Next,
13951                    ),
13952                    SelectionGoal::None,
13953                )
13954            });
13955        })
13956    }
13957
13958    pub fn move_to_end_of_excerpt(
13959        &mut self,
13960        _: &MoveToEndOfExcerpt,
13961        window: &mut Window,
13962        cx: &mut Context<Self>,
13963    ) {
13964        if matches!(self.mode, EditorMode::SingleLine) {
13965            cx.propagate();
13966            return;
13967        }
13968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13969        self.change_selections(Default::default(), window, cx, |s| {
13970            s.move_with(|map, selection| {
13971                selection.collapse_to(
13972                    movement::end_of_excerpt(
13973                        map,
13974                        selection.head(),
13975                        workspace::searchable::Direction::Next,
13976                    ),
13977                    SelectionGoal::None,
13978                )
13979            });
13980        })
13981    }
13982
13983    pub fn move_to_end_of_previous_excerpt(
13984        &mut self,
13985        _: &MoveToEndOfPreviousExcerpt,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        if matches!(self.mode, EditorMode::SingleLine) {
13990            cx.propagate();
13991            return;
13992        }
13993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13994        self.change_selections(Default::default(), window, cx, |s| {
13995            s.move_with(|map, selection| {
13996                selection.collapse_to(
13997                    movement::end_of_excerpt(
13998                        map,
13999                        selection.head(),
14000                        workspace::searchable::Direction::Prev,
14001                    ),
14002                    SelectionGoal::None,
14003                )
14004            });
14005        })
14006    }
14007
14008    pub fn select_to_start_of_excerpt(
14009        &mut self,
14010        _: &SelectToStartOfExcerpt,
14011        window: &mut Window,
14012        cx: &mut Context<Self>,
14013    ) {
14014        if matches!(self.mode, EditorMode::SingleLine) {
14015            cx.propagate();
14016            return;
14017        }
14018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14019        self.change_selections(Default::default(), window, cx, |s| {
14020            s.move_heads_with(|map, head, _| {
14021                (
14022                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14023                    SelectionGoal::None,
14024                )
14025            });
14026        })
14027    }
14028
14029    pub fn select_to_start_of_next_excerpt(
14030        &mut self,
14031        _: &SelectToStartOfNextExcerpt,
14032        window: &mut Window,
14033        cx: &mut Context<Self>,
14034    ) {
14035        if matches!(self.mode, EditorMode::SingleLine) {
14036            cx.propagate();
14037            return;
14038        }
14039        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14040        self.change_selections(Default::default(), window, cx, |s| {
14041            s.move_heads_with(|map, head, _| {
14042                (
14043                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14044                    SelectionGoal::None,
14045                )
14046            });
14047        })
14048    }
14049
14050    pub fn select_to_end_of_excerpt(
14051        &mut self,
14052        _: &SelectToEndOfExcerpt,
14053        window: &mut Window,
14054        cx: &mut Context<Self>,
14055    ) {
14056        if matches!(self.mode, EditorMode::SingleLine) {
14057            cx.propagate();
14058            return;
14059        }
14060        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14061        self.change_selections(Default::default(), window, cx, |s| {
14062            s.move_heads_with(|map, head, _| {
14063                (
14064                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14065                    SelectionGoal::None,
14066                )
14067            });
14068        })
14069    }
14070
14071    pub fn select_to_end_of_previous_excerpt(
14072        &mut self,
14073        _: &SelectToEndOfPreviousExcerpt,
14074        window: &mut Window,
14075        cx: &mut Context<Self>,
14076    ) {
14077        if matches!(self.mode, EditorMode::SingleLine) {
14078            cx.propagate();
14079            return;
14080        }
14081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14082        self.change_selections(Default::default(), window, cx, |s| {
14083            s.move_heads_with(|map, head, _| {
14084                (
14085                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14086                    SelectionGoal::None,
14087                )
14088            });
14089        })
14090    }
14091
14092    pub fn move_to_beginning(
14093        &mut self,
14094        _: &MoveToBeginning,
14095        window: &mut Window,
14096        cx: &mut Context<Self>,
14097    ) {
14098        if matches!(self.mode, EditorMode::SingleLine) {
14099            cx.propagate();
14100            return;
14101        }
14102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14103        self.change_selections(Default::default(), window, cx, |s| {
14104            s.select_ranges(vec![0..0]);
14105        });
14106    }
14107
14108    pub fn select_to_beginning(
14109        &mut self,
14110        _: &SelectToBeginning,
14111        window: &mut Window,
14112        cx: &mut Context<Self>,
14113    ) {
14114        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14115        selection.set_head(Point::zero(), SelectionGoal::None);
14116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14117        self.change_selections(Default::default(), window, cx, |s| {
14118            s.select(vec![selection]);
14119        });
14120    }
14121
14122    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14123        if matches!(self.mode, EditorMode::SingleLine) {
14124            cx.propagate();
14125            return;
14126        }
14127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14128        let cursor = self.buffer.read(cx).read(cx).len();
14129        self.change_selections(Default::default(), window, cx, |s| {
14130            s.select_ranges(vec![cursor..cursor])
14131        });
14132    }
14133
14134    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14135        self.nav_history = nav_history;
14136    }
14137
14138    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14139        self.nav_history.as_ref()
14140    }
14141
14142    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14143        self.push_to_nav_history(
14144            self.selections.newest_anchor().head(),
14145            None,
14146            false,
14147            true,
14148            cx,
14149        );
14150    }
14151
14152    fn push_to_nav_history(
14153        &mut self,
14154        cursor_anchor: Anchor,
14155        new_position: Option<Point>,
14156        is_deactivate: bool,
14157        always: bool,
14158        cx: &mut Context<Self>,
14159    ) {
14160        if let Some(nav_history) = self.nav_history.as_mut() {
14161            let buffer = self.buffer.read(cx).read(cx);
14162            let cursor_position = cursor_anchor.to_point(&buffer);
14163            let scroll_state = self.scroll_manager.anchor();
14164            let scroll_top_row = scroll_state.top_row(&buffer);
14165            drop(buffer);
14166
14167            if let Some(new_position) = new_position {
14168                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14169                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14170                    return;
14171                }
14172            }
14173
14174            nav_history.push(
14175                Some(NavigationData {
14176                    cursor_anchor,
14177                    cursor_position,
14178                    scroll_anchor: scroll_state,
14179                    scroll_top_row,
14180                }),
14181                cx,
14182            );
14183            cx.emit(EditorEvent::PushedToNavHistory {
14184                anchor: cursor_anchor,
14185                is_deactivate,
14186            })
14187        }
14188    }
14189
14190    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14192        let buffer = self.buffer.read(cx).snapshot(cx);
14193        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14194        selection.set_head(buffer.len(), SelectionGoal::None);
14195        self.change_selections(Default::default(), window, cx, |s| {
14196            s.select(vec![selection]);
14197        });
14198    }
14199
14200    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14202        let end = self.buffer.read(cx).read(cx).len();
14203        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14204            s.select_ranges(vec![0..end]);
14205        });
14206    }
14207
14208    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14209        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14210        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14211        let mut selections = self.selections.all::<Point>(&display_map);
14212        let max_point = display_map.buffer_snapshot().max_point();
14213        for selection in &mut selections {
14214            let rows = selection.spanned_rows(true, &display_map);
14215            selection.start = Point::new(rows.start.0, 0);
14216            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14217            selection.reversed = false;
14218        }
14219        self.change_selections(Default::default(), window, cx, |s| {
14220            s.select(selections);
14221        });
14222    }
14223
14224    pub fn split_selection_into_lines(
14225        &mut self,
14226        action: &SplitSelectionIntoLines,
14227        window: &mut Window,
14228        cx: &mut Context<Self>,
14229    ) {
14230        let selections = self
14231            .selections
14232            .all::<Point>(&self.display_snapshot(cx))
14233            .into_iter()
14234            .map(|selection| selection.start..selection.end)
14235            .collect::<Vec<_>>();
14236        self.unfold_ranges(&selections, true, true, cx);
14237
14238        let mut new_selection_ranges = Vec::new();
14239        {
14240            let buffer = self.buffer.read(cx).read(cx);
14241            for selection in selections {
14242                for row in selection.start.row..selection.end.row {
14243                    let line_start = Point::new(row, 0);
14244                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14245
14246                    if action.keep_selections {
14247                        // Keep the selection range for each line
14248                        let selection_start = if row == selection.start.row {
14249                            selection.start
14250                        } else {
14251                            line_start
14252                        };
14253                        new_selection_ranges.push(selection_start..line_end);
14254                    } else {
14255                        // Collapse to cursor at end of line
14256                        new_selection_ranges.push(line_end..line_end);
14257                    }
14258                }
14259
14260                let is_multiline_selection = selection.start.row != selection.end.row;
14261                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14262                // so this action feels more ergonomic when paired with other selection operations
14263                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14264                if !should_skip_last {
14265                    if action.keep_selections {
14266                        if is_multiline_selection {
14267                            let line_start = Point::new(selection.end.row, 0);
14268                            new_selection_ranges.push(line_start..selection.end);
14269                        } else {
14270                            new_selection_ranges.push(selection.start..selection.end);
14271                        }
14272                    } else {
14273                        new_selection_ranges.push(selection.end..selection.end);
14274                    }
14275                }
14276            }
14277        }
14278        self.change_selections(Default::default(), window, cx, |s| {
14279            s.select_ranges(new_selection_ranges);
14280        });
14281    }
14282
14283    pub fn add_selection_above(
14284        &mut self,
14285        action: &AddSelectionAbove,
14286        window: &mut Window,
14287        cx: &mut Context<Self>,
14288    ) {
14289        self.add_selection(true, action.skip_soft_wrap, window, cx);
14290    }
14291
14292    pub fn add_selection_below(
14293        &mut self,
14294        action: &AddSelectionBelow,
14295        window: &mut Window,
14296        cx: &mut Context<Self>,
14297    ) {
14298        self.add_selection(false, action.skip_soft_wrap, window, cx);
14299    }
14300
14301    fn add_selection(
14302        &mut self,
14303        above: bool,
14304        skip_soft_wrap: bool,
14305        window: &mut Window,
14306        cx: &mut Context<Self>,
14307    ) {
14308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14309
14310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14311        let all_selections = self.selections.all::<Point>(&display_map);
14312        let text_layout_details = self.text_layout_details(window);
14313
14314        let (mut columnar_selections, new_selections_to_columnarize) = {
14315            if let Some(state) = self.add_selections_state.as_ref() {
14316                let columnar_selection_ids: HashSet<_> = state
14317                    .groups
14318                    .iter()
14319                    .flat_map(|group| group.stack.iter())
14320                    .copied()
14321                    .collect();
14322
14323                all_selections
14324                    .into_iter()
14325                    .partition(|s| columnar_selection_ids.contains(&s.id))
14326            } else {
14327                (Vec::new(), all_selections)
14328            }
14329        };
14330
14331        let mut state = self
14332            .add_selections_state
14333            .take()
14334            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14335
14336        for selection in new_selections_to_columnarize {
14337            let range = selection.display_range(&display_map).sorted();
14338            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14339            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14340            let positions = start_x.min(end_x)..start_x.max(end_x);
14341            let mut stack = Vec::new();
14342            for row in range.start.row().0..=range.end.row().0 {
14343                if let Some(selection) = self.selections.build_columnar_selection(
14344                    &display_map,
14345                    DisplayRow(row),
14346                    &positions,
14347                    selection.reversed,
14348                    &text_layout_details,
14349                ) {
14350                    stack.push(selection.id);
14351                    columnar_selections.push(selection);
14352                }
14353            }
14354            if !stack.is_empty() {
14355                if above {
14356                    stack.reverse();
14357                }
14358                state.groups.push(AddSelectionsGroup { above, stack });
14359            }
14360        }
14361
14362        let mut final_selections = Vec::new();
14363        let end_row = if above {
14364            DisplayRow(0)
14365        } else {
14366            display_map.max_point().row()
14367        };
14368
14369        let mut last_added_item_per_group = HashMap::default();
14370        for group in state.groups.iter_mut() {
14371            if let Some(last_id) = group.stack.last() {
14372                last_added_item_per_group.insert(*last_id, group);
14373            }
14374        }
14375
14376        for selection in columnar_selections {
14377            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14378                if above == group.above {
14379                    let range = selection.display_range(&display_map).sorted();
14380                    debug_assert_eq!(range.start.row(), range.end.row());
14381                    let mut row = range.start.row();
14382                    let positions =
14383                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14384                            Pixels::from(start)..Pixels::from(end)
14385                        } else {
14386                            let start_x =
14387                                display_map.x_for_display_point(range.start, &text_layout_details);
14388                            let end_x =
14389                                display_map.x_for_display_point(range.end, &text_layout_details);
14390                            start_x.min(end_x)..start_x.max(end_x)
14391                        };
14392
14393                    let mut maybe_new_selection = None;
14394                    let direction = if above { -1 } else { 1 };
14395
14396                    while row != end_row {
14397                        if skip_soft_wrap {
14398                            row = display_map
14399                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14400                                .row();
14401                        } else if above {
14402                            row.0 -= 1;
14403                        } else {
14404                            row.0 += 1;
14405                        }
14406
14407                        if let Some(new_selection) = self.selections.build_columnar_selection(
14408                            &display_map,
14409                            row,
14410                            &positions,
14411                            selection.reversed,
14412                            &text_layout_details,
14413                        ) {
14414                            maybe_new_selection = Some(new_selection);
14415                            break;
14416                        }
14417                    }
14418
14419                    if let Some(new_selection) = maybe_new_selection {
14420                        group.stack.push(new_selection.id);
14421                        if above {
14422                            final_selections.push(new_selection);
14423                            final_selections.push(selection);
14424                        } else {
14425                            final_selections.push(selection);
14426                            final_selections.push(new_selection);
14427                        }
14428                    } else {
14429                        final_selections.push(selection);
14430                    }
14431                } else {
14432                    group.stack.pop();
14433                }
14434            } else {
14435                final_selections.push(selection);
14436            }
14437        }
14438
14439        self.change_selections(Default::default(), window, cx, |s| {
14440            s.select(final_selections);
14441        });
14442
14443        let final_selection_ids: HashSet<_> = self
14444            .selections
14445            .all::<Point>(&display_map)
14446            .iter()
14447            .map(|s| s.id)
14448            .collect();
14449        state.groups.retain_mut(|group| {
14450            // selections might get merged above so we remove invalid items from stacks
14451            group.stack.retain(|id| final_selection_ids.contains(id));
14452
14453            // single selection in stack can be treated as initial state
14454            group.stack.len() > 1
14455        });
14456
14457        if !state.groups.is_empty() {
14458            self.add_selections_state = Some(state);
14459        }
14460    }
14461
14462    fn select_match_ranges(
14463        &mut self,
14464        range: Range<usize>,
14465        reversed: bool,
14466        replace_newest: bool,
14467        auto_scroll: Option<Autoscroll>,
14468        window: &mut Window,
14469        cx: &mut Context<Editor>,
14470    ) {
14471        self.unfold_ranges(
14472            std::slice::from_ref(&range),
14473            false,
14474            auto_scroll.is_some(),
14475            cx,
14476        );
14477        let effects = if let Some(scroll) = auto_scroll {
14478            SelectionEffects::scroll(scroll)
14479        } else {
14480            SelectionEffects::no_scroll()
14481        };
14482        self.change_selections(effects, window, cx, |s| {
14483            if replace_newest {
14484                s.delete(s.newest_anchor().id);
14485            }
14486            if reversed {
14487                s.insert_range(range.end..range.start);
14488            } else {
14489                s.insert_range(range);
14490            }
14491        });
14492    }
14493
14494    pub fn select_next_match_internal(
14495        &mut self,
14496        display_map: &DisplaySnapshot,
14497        replace_newest: bool,
14498        autoscroll: Option<Autoscroll>,
14499        window: &mut Window,
14500        cx: &mut Context<Self>,
14501    ) -> Result<()> {
14502        let buffer = display_map.buffer_snapshot();
14503        let mut selections = self.selections.all::<usize>(&display_map);
14504        if let Some(mut select_next_state) = self.select_next_state.take() {
14505            let query = &select_next_state.query;
14506            if !select_next_state.done {
14507                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14508                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14509                let mut next_selected_range = None;
14510
14511                // Collect and sort selection ranges for efficient overlap checking
14512                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14513                selection_ranges.sort_by_key(|r| r.start);
14514
14515                let bytes_after_last_selection =
14516                    buffer.bytes_in_range(last_selection.end..buffer.len());
14517                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14518                let query_matches = query
14519                    .stream_find_iter(bytes_after_last_selection)
14520                    .map(|result| (last_selection.end, result))
14521                    .chain(
14522                        query
14523                            .stream_find_iter(bytes_before_first_selection)
14524                            .map(|result| (0, result)),
14525                    );
14526
14527                for (start_offset, query_match) in query_matches {
14528                    let query_match = query_match.unwrap(); // can only fail due to I/O
14529                    let offset_range =
14530                        start_offset + query_match.start()..start_offset + query_match.end();
14531
14532                    if !select_next_state.wordwise
14533                        || (!buffer.is_inside_word(offset_range.start, None)
14534                            && !buffer.is_inside_word(offset_range.end, None))
14535                    {
14536                        // Use binary search to check for overlap (O(log n))
14537                        let overlaps = selection_ranges
14538                            .binary_search_by(|range| {
14539                                if range.end <= offset_range.start {
14540                                    std::cmp::Ordering::Less
14541                                } else if range.start >= offset_range.end {
14542                                    std::cmp::Ordering::Greater
14543                                } else {
14544                                    std::cmp::Ordering::Equal
14545                                }
14546                            })
14547                            .is_ok();
14548
14549                        if !overlaps {
14550                            next_selected_range = Some(offset_range);
14551                            break;
14552                        }
14553                    }
14554                }
14555
14556                if let Some(next_selected_range) = next_selected_range {
14557                    self.select_match_ranges(
14558                        next_selected_range,
14559                        last_selection.reversed,
14560                        replace_newest,
14561                        autoscroll,
14562                        window,
14563                        cx,
14564                    );
14565                } else {
14566                    select_next_state.done = true;
14567                }
14568            }
14569
14570            self.select_next_state = Some(select_next_state);
14571        } else {
14572            let mut only_carets = true;
14573            let mut same_text_selected = true;
14574            let mut selected_text = None;
14575
14576            let mut selections_iter = selections.iter().peekable();
14577            while let Some(selection) = selections_iter.next() {
14578                if selection.start != selection.end {
14579                    only_carets = false;
14580                }
14581
14582                if same_text_selected {
14583                    if selected_text.is_none() {
14584                        selected_text =
14585                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14586                    }
14587
14588                    if let Some(next_selection) = selections_iter.peek() {
14589                        if next_selection.range().len() == selection.range().len() {
14590                            let next_selected_text = buffer
14591                                .text_for_range(next_selection.range())
14592                                .collect::<String>();
14593                            if Some(next_selected_text) != selected_text {
14594                                same_text_selected = false;
14595                                selected_text = None;
14596                            }
14597                        } else {
14598                            same_text_selected = false;
14599                            selected_text = None;
14600                        }
14601                    }
14602                }
14603            }
14604
14605            if only_carets {
14606                for selection in &mut selections {
14607                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14608                    selection.start = word_range.start;
14609                    selection.end = word_range.end;
14610                    selection.goal = SelectionGoal::None;
14611                    selection.reversed = false;
14612                    self.select_match_ranges(
14613                        selection.start..selection.end,
14614                        selection.reversed,
14615                        replace_newest,
14616                        autoscroll,
14617                        window,
14618                        cx,
14619                    );
14620                }
14621
14622                if selections.len() == 1 {
14623                    let selection = selections
14624                        .last()
14625                        .expect("ensured that there's only one selection");
14626                    let query = buffer
14627                        .text_for_range(selection.start..selection.end)
14628                        .collect::<String>();
14629                    let is_empty = query.is_empty();
14630                    let select_state = SelectNextState {
14631                        query: AhoCorasick::new(&[query])?,
14632                        wordwise: true,
14633                        done: is_empty,
14634                    };
14635                    self.select_next_state = Some(select_state);
14636                } else {
14637                    self.select_next_state = None;
14638                }
14639            } else if let Some(selected_text) = selected_text {
14640                self.select_next_state = Some(SelectNextState {
14641                    query: AhoCorasick::new(&[selected_text])?,
14642                    wordwise: false,
14643                    done: false,
14644                });
14645                self.select_next_match_internal(
14646                    display_map,
14647                    replace_newest,
14648                    autoscroll,
14649                    window,
14650                    cx,
14651                )?;
14652            }
14653        }
14654        Ok(())
14655    }
14656
14657    pub fn select_all_matches(
14658        &mut self,
14659        _action: &SelectAllMatches,
14660        window: &mut Window,
14661        cx: &mut Context<Self>,
14662    ) -> Result<()> {
14663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14664
14665        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14666
14667        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14668        let Some(select_next_state) = self.select_next_state.as_mut() else {
14669            return Ok(());
14670        };
14671        if select_next_state.done {
14672            return Ok(());
14673        }
14674
14675        let mut new_selections = Vec::new();
14676
14677        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14678        let buffer = display_map.buffer_snapshot();
14679        let query_matches = select_next_state
14680            .query
14681            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14682
14683        for query_match in query_matches.into_iter() {
14684            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14685            let offset_range = if reversed {
14686                query_match.end()..query_match.start()
14687            } else {
14688                query_match.start()..query_match.end()
14689            };
14690
14691            if !select_next_state.wordwise
14692                || (!buffer.is_inside_word(offset_range.start, None)
14693                    && !buffer.is_inside_word(offset_range.end, None))
14694            {
14695                new_selections.push(offset_range.start..offset_range.end);
14696            }
14697        }
14698
14699        select_next_state.done = true;
14700
14701        if new_selections.is_empty() {
14702            log::error!("bug: new_selections is empty in select_all_matches");
14703            return Ok(());
14704        }
14705
14706        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14707        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14708            selections.select_ranges(new_selections)
14709        });
14710
14711        Ok(())
14712    }
14713
14714    pub fn select_next(
14715        &mut self,
14716        action: &SelectNext,
14717        window: &mut Window,
14718        cx: &mut Context<Self>,
14719    ) -> Result<()> {
14720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14721        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14722        self.select_next_match_internal(
14723            &display_map,
14724            action.replace_newest,
14725            Some(Autoscroll::newest()),
14726            window,
14727            cx,
14728        )?;
14729        Ok(())
14730    }
14731
14732    pub fn select_previous(
14733        &mut self,
14734        action: &SelectPrevious,
14735        window: &mut Window,
14736        cx: &mut Context<Self>,
14737    ) -> Result<()> {
14738        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14739        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14740        let buffer = display_map.buffer_snapshot();
14741        let mut selections = self.selections.all::<usize>(&display_map);
14742        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14743            let query = &select_prev_state.query;
14744            if !select_prev_state.done {
14745                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14746                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14747                let mut next_selected_range = None;
14748                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14749                let bytes_before_last_selection =
14750                    buffer.reversed_bytes_in_range(0..last_selection.start);
14751                let bytes_after_first_selection =
14752                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14753                let query_matches = query
14754                    .stream_find_iter(bytes_before_last_selection)
14755                    .map(|result| (last_selection.start, result))
14756                    .chain(
14757                        query
14758                            .stream_find_iter(bytes_after_first_selection)
14759                            .map(|result| (buffer.len(), result)),
14760                    );
14761                for (end_offset, query_match) in query_matches {
14762                    let query_match = query_match.unwrap(); // can only fail due to I/O
14763                    let offset_range =
14764                        end_offset - query_match.end()..end_offset - query_match.start();
14765
14766                    if !select_prev_state.wordwise
14767                        || (!buffer.is_inside_word(offset_range.start, None)
14768                            && !buffer.is_inside_word(offset_range.end, None))
14769                    {
14770                        next_selected_range = Some(offset_range);
14771                        break;
14772                    }
14773                }
14774
14775                if let Some(next_selected_range) = next_selected_range {
14776                    self.select_match_ranges(
14777                        next_selected_range,
14778                        last_selection.reversed,
14779                        action.replace_newest,
14780                        Some(Autoscroll::newest()),
14781                        window,
14782                        cx,
14783                    );
14784                } else {
14785                    select_prev_state.done = true;
14786                }
14787            }
14788
14789            self.select_prev_state = Some(select_prev_state);
14790        } else {
14791            let mut only_carets = true;
14792            let mut same_text_selected = true;
14793            let mut selected_text = None;
14794
14795            let mut selections_iter = selections.iter().peekable();
14796            while let Some(selection) = selections_iter.next() {
14797                if selection.start != selection.end {
14798                    only_carets = false;
14799                }
14800
14801                if same_text_selected {
14802                    if selected_text.is_none() {
14803                        selected_text =
14804                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14805                    }
14806
14807                    if let Some(next_selection) = selections_iter.peek() {
14808                        if next_selection.range().len() == selection.range().len() {
14809                            let next_selected_text = buffer
14810                                .text_for_range(next_selection.range())
14811                                .collect::<String>();
14812                            if Some(next_selected_text) != selected_text {
14813                                same_text_selected = false;
14814                                selected_text = None;
14815                            }
14816                        } else {
14817                            same_text_selected = false;
14818                            selected_text = None;
14819                        }
14820                    }
14821                }
14822            }
14823
14824            if only_carets {
14825                for selection in &mut selections {
14826                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14827                    selection.start = word_range.start;
14828                    selection.end = word_range.end;
14829                    selection.goal = SelectionGoal::None;
14830                    selection.reversed = false;
14831                    self.select_match_ranges(
14832                        selection.start..selection.end,
14833                        selection.reversed,
14834                        action.replace_newest,
14835                        Some(Autoscroll::newest()),
14836                        window,
14837                        cx,
14838                    );
14839                }
14840                if selections.len() == 1 {
14841                    let selection = selections
14842                        .last()
14843                        .expect("ensured that there's only one selection");
14844                    let query = buffer
14845                        .text_for_range(selection.start..selection.end)
14846                        .collect::<String>();
14847                    let is_empty = query.is_empty();
14848                    let select_state = SelectNextState {
14849                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14850                        wordwise: true,
14851                        done: is_empty,
14852                    };
14853                    self.select_prev_state = Some(select_state);
14854                } else {
14855                    self.select_prev_state = None;
14856                }
14857            } else if let Some(selected_text) = selected_text {
14858                self.select_prev_state = Some(SelectNextState {
14859                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14860                    wordwise: false,
14861                    done: false,
14862                });
14863                self.select_previous(action, window, cx)?;
14864            }
14865        }
14866        Ok(())
14867    }
14868
14869    pub fn find_next_match(
14870        &mut self,
14871        _: &FindNextMatch,
14872        window: &mut Window,
14873        cx: &mut Context<Self>,
14874    ) -> Result<()> {
14875        let selections = self.selections.disjoint_anchors_arc();
14876        match selections.first() {
14877            Some(first) if selections.len() >= 2 => {
14878                self.change_selections(Default::default(), window, cx, |s| {
14879                    s.select_ranges([first.range()]);
14880                });
14881            }
14882            _ => self.select_next(
14883                &SelectNext {
14884                    replace_newest: true,
14885                },
14886                window,
14887                cx,
14888            )?,
14889        }
14890        Ok(())
14891    }
14892
14893    pub fn find_previous_match(
14894        &mut self,
14895        _: &FindPreviousMatch,
14896        window: &mut Window,
14897        cx: &mut Context<Self>,
14898    ) -> Result<()> {
14899        let selections = self.selections.disjoint_anchors_arc();
14900        match selections.last() {
14901            Some(last) if selections.len() >= 2 => {
14902                self.change_selections(Default::default(), window, cx, |s| {
14903                    s.select_ranges([last.range()]);
14904                });
14905            }
14906            _ => self.select_previous(
14907                &SelectPrevious {
14908                    replace_newest: true,
14909                },
14910                window,
14911                cx,
14912            )?,
14913        }
14914        Ok(())
14915    }
14916
14917    pub fn toggle_comments(
14918        &mut self,
14919        action: &ToggleComments,
14920        window: &mut Window,
14921        cx: &mut Context<Self>,
14922    ) {
14923        if self.read_only(cx) {
14924            return;
14925        }
14926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14927        let text_layout_details = &self.text_layout_details(window);
14928        self.transact(window, cx, |this, window, cx| {
14929            let mut selections = this
14930                .selections
14931                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14932            let mut edits = Vec::new();
14933            let mut selection_edit_ranges = Vec::new();
14934            let mut last_toggled_row = None;
14935            let snapshot = this.buffer.read(cx).read(cx);
14936            let empty_str: Arc<str> = Arc::default();
14937            let mut suffixes_inserted = Vec::new();
14938            let ignore_indent = action.ignore_indent;
14939
14940            fn comment_prefix_range(
14941                snapshot: &MultiBufferSnapshot,
14942                row: MultiBufferRow,
14943                comment_prefix: &str,
14944                comment_prefix_whitespace: &str,
14945                ignore_indent: bool,
14946            ) -> Range<Point> {
14947                let indent_size = if ignore_indent {
14948                    0
14949                } else {
14950                    snapshot.indent_size_for_line(row).len
14951                };
14952
14953                let start = Point::new(row.0, indent_size);
14954
14955                let mut line_bytes = snapshot
14956                    .bytes_in_range(start..snapshot.max_point())
14957                    .flatten()
14958                    .copied();
14959
14960                // If this line currently begins with the line comment prefix, then record
14961                // the range containing the prefix.
14962                if line_bytes
14963                    .by_ref()
14964                    .take(comment_prefix.len())
14965                    .eq(comment_prefix.bytes())
14966                {
14967                    // Include any whitespace that matches the comment prefix.
14968                    let matching_whitespace_len = line_bytes
14969                        .zip(comment_prefix_whitespace.bytes())
14970                        .take_while(|(a, b)| a == b)
14971                        .count() as u32;
14972                    let end = Point::new(
14973                        start.row,
14974                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14975                    );
14976                    start..end
14977                } else {
14978                    start..start
14979                }
14980            }
14981
14982            fn comment_suffix_range(
14983                snapshot: &MultiBufferSnapshot,
14984                row: MultiBufferRow,
14985                comment_suffix: &str,
14986                comment_suffix_has_leading_space: bool,
14987            ) -> Range<Point> {
14988                let end = Point::new(row.0, snapshot.line_len(row));
14989                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14990
14991                let mut line_end_bytes = snapshot
14992                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14993                    .flatten()
14994                    .copied();
14995
14996                let leading_space_len = if suffix_start_column > 0
14997                    && line_end_bytes.next() == Some(b' ')
14998                    && comment_suffix_has_leading_space
14999                {
15000                    1
15001                } else {
15002                    0
15003                };
15004
15005                // If this line currently begins with the line comment prefix, then record
15006                // the range containing the prefix.
15007                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15008                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15009                    start..end
15010                } else {
15011                    end..end
15012                }
15013            }
15014
15015            // TODO: Handle selections that cross excerpts
15016            for selection in &mut selections {
15017                let start_column = snapshot
15018                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15019                    .len;
15020                let language = if let Some(language) =
15021                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15022                {
15023                    language
15024                } else {
15025                    continue;
15026                };
15027
15028                selection_edit_ranges.clear();
15029
15030                // If multiple selections contain a given row, avoid processing that
15031                // row more than once.
15032                let mut start_row = MultiBufferRow(selection.start.row);
15033                if last_toggled_row == Some(start_row) {
15034                    start_row = start_row.next_row();
15035                }
15036                let end_row =
15037                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15038                        MultiBufferRow(selection.end.row - 1)
15039                    } else {
15040                        MultiBufferRow(selection.end.row)
15041                    };
15042                last_toggled_row = Some(end_row);
15043
15044                if start_row > end_row {
15045                    continue;
15046                }
15047
15048                // If the language has line comments, toggle those.
15049                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15050
15051                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15052                if ignore_indent {
15053                    full_comment_prefixes = full_comment_prefixes
15054                        .into_iter()
15055                        .map(|s| Arc::from(s.trim_end()))
15056                        .collect();
15057                }
15058
15059                if !full_comment_prefixes.is_empty() {
15060                    let first_prefix = full_comment_prefixes
15061                        .first()
15062                        .expect("prefixes is non-empty");
15063                    let prefix_trimmed_lengths = full_comment_prefixes
15064                        .iter()
15065                        .map(|p| p.trim_end_matches(' ').len())
15066                        .collect::<SmallVec<[usize; 4]>>();
15067
15068                    let mut all_selection_lines_are_comments = true;
15069
15070                    for row in start_row.0..=end_row.0 {
15071                        let row = MultiBufferRow(row);
15072                        if start_row < end_row && snapshot.is_line_blank(row) {
15073                            continue;
15074                        }
15075
15076                        let prefix_range = full_comment_prefixes
15077                            .iter()
15078                            .zip(prefix_trimmed_lengths.iter().copied())
15079                            .map(|(prefix, trimmed_prefix_len)| {
15080                                comment_prefix_range(
15081                                    snapshot.deref(),
15082                                    row,
15083                                    &prefix[..trimmed_prefix_len],
15084                                    &prefix[trimmed_prefix_len..],
15085                                    ignore_indent,
15086                                )
15087                            })
15088                            .max_by_key(|range| range.end.column - range.start.column)
15089                            .expect("prefixes is non-empty");
15090
15091                        if prefix_range.is_empty() {
15092                            all_selection_lines_are_comments = false;
15093                        }
15094
15095                        selection_edit_ranges.push(prefix_range);
15096                    }
15097
15098                    if all_selection_lines_are_comments {
15099                        edits.extend(
15100                            selection_edit_ranges
15101                                .iter()
15102                                .cloned()
15103                                .map(|range| (range, empty_str.clone())),
15104                        );
15105                    } else {
15106                        let min_column = selection_edit_ranges
15107                            .iter()
15108                            .map(|range| range.start.column)
15109                            .min()
15110                            .unwrap_or(0);
15111                        edits.extend(selection_edit_ranges.iter().map(|range| {
15112                            let position = Point::new(range.start.row, min_column);
15113                            (position..position, first_prefix.clone())
15114                        }));
15115                    }
15116                } else if let Some(BlockCommentConfig {
15117                    start: full_comment_prefix,
15118                    end: comment_suffix,
15119                    ..
15120                }) = language.block_comment()
15121                {
15122                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15123                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15124                    let prefix_range = comment_prefix_range(
15125                        snapshot.deref(),
15126                        start_row,
15127                        comment_prefix,
15128                        comment_prefix_whitespace,
15129                        ignore_indent,
15130                    );
15131                    let suffix_range = comment_suffix_range(
15132                        snapshot.deref(),
15133                        end_row,
15134                        comment_suffix.trim_start_matches(' '),
15135                        comment_suffix.starts_with(' '),
15136                    );
15137
15138                    if prefix_range.is_empty() || suffix_range.is_empty() {
15139                        edits.push((
15140                            prefix_range.start..prefix_range.start,
15141                            full_comment_prefix.clone(),
15142                        ));
15143                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15144                        suffixes_inserted.push((end_row, comment_suffix.len()));
15145                    } else {
15146                        edits.push((prefix_range, empty_str.clone()));
15147                        edits.push((suffix_range, empty_str.clone()));
15148                    }
15149                } else {
15150                    continue;
15151                }
15152            }
15153
15154            drop(snapshot);
15155            this.buffer.update(cx, |buffer, cx| {
15156                buffer.edit(edits, None, cx);
15157            });
15158
15159            // Adjust selections so that they end before any comment suffixes that
15160            // were inserted.
15161            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15162            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15163            let snapshot = this.buffer.read(cx).read(cx);
15164            for selection in &mut selections {
15165                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15166                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15167                        Ordering::Less => {
15168                            suffixes_inserted.next();
15169                            continue;
15170                        }
15171                        Ordering::Greater => break,
15172                        Ordering::Equal => {
15173                            if selection.end.column == snapshot.line_len(row) {
15174                                if selection.is_empty() {
15175                                    selection.start.column -= suffix_len as u32;
15176                                }
15177                                selection.end.column -= suffix_len as u32;
15178                            }
15179                            break;
15180                        }
15181                    }
15182                }
15183            }
15184
15185            drop(snapshot);
15186            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15187
15188            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15189            let selections_on_single_row = selections.windows(2).all(|selections| {
15190                selections[0].start.row == selections[1].start.row
15191                    && selections[0].end.row == selections[1].end.row
15192                    && selections[0].start.row == selections[0].end.row
15193            });
15194            let selections_selecting = selections
15195                .iter()
15196                .any(|selection| selection.start != selection.end);
15197            let advance_downwards = action.advance_downwards
15198                && selections_on_single_row
15199                && !selections_selecting
15200                && !matches!(this.mode, EditorMode::SingleLine);
15201
15202            if advance_downwards {
15203                let snapshot = this.buffer.read(cx).snapshot(cx);
15204
15205                this.change_selections(Default::default(), window, cx, |s| {
15206                    s.move_cursors_with(|display_snapshot, display_point, _| {
15207                        let mut point = display_point.to_point(display_snapshot);
15208                        point.row += 1;
15209                        point = snapshot.clip_point(point, Bias::Left);
15210                        let display_point = point.to_display_point(display_snapshot);
15211                        let goal = SelectionGoal::HorizontalPosition(
15212                            display_snapshot
15213                                .x_for_display_point(display_point, text_layout_details)
15214                                .into(),
15215                        );
15216                        (display_point, goal)
15217                    })
15218                });
15219            }
15220        });
15221    }
15222
15223    pub fn select_enclosing_symbol(
15224        &mut self,
15225        _: &SelectEnclosingSymbol,
15226        window: &mut Window,
15227        cx: &mut Context<Self>,
15228    ) {
15229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15230
15231        let buffer = self.buffer.read(cx).snapshot(cx);
15232        let old_selections = self
15233            .selections
15234            .all::<usize>(&self.display_snapshot(cx))
15235            .into_boxed_slice();
15236
15237        fn update_selection(
15238            selection: &Selection<usize>,
15239            buffer_snap: &MultiBufferSnapshot,
15240        ) -> Option<Selection<usize>> {
15241            let cursor = selection.head();
15242            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15243            for symbol in symbols.iter().rev() {
15244                let start = symbol.range.start.to_offset(buffer_snap);
15245                let end = symbol.range.end.to_offset(buffer_snap);
15246                let new_range = start..end;
15247                if start < selection.start || end > selection.end {
15248                    return Some(Selection {
15249                        id: selection.id,
15250                        start: new_range.start,
15251                        end: new_range.end,
15252                        goal: SelectionGoal::None,
15253                        reversed: selection.reversed,
15254                    });
15255                }
15256            }
15257            None
15258        }
15259
15260        let mut selected_larger_symbol = false;
15261        let new_selections = old_selections
15262            .iter()
15263            .map(|selection| match update_selection(selection, &buffer) {
15264                Some(new_selection) => {
15265                    if new_selection.range() != selection.range() {
15266                        selected_larger_symbol = true;
15267                    }
15268                    new_selection
15269                }
15270                None => selection.clone(),
15271            })
15272            .collect::<Vec<_>>();
15273
15274        if selected_larger_symbol {
15275            self.change_selections(Default::default(), window, cx, |s| {
15276                s.select(new_selections);
15277            });
15278        }
15279    }
15280
15281    pub fn select_larger_syntax_node(
15282        &mut self,
15283        _: &SelectLargerSyntaxNode,
15284        window: &mut Window,
15285        cx: &mut Context<Self>,
15286    ) {
15287        let Some(visible_row_count) = self.visible_row_count() else {
15288            return;
15289        };
15290        let old_selections: Box<[_]> = self
15291            .selections
15292            .all::<usize>(&self.display_snapshot(cx))
15293            .into();
15294        if old_selections.is_empty() {
15295            return;
15296        }
15297
15298        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15299
15300        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15301        let buffer = self.buffer.read(cx).snapshot(cx);
15302
15303        let mut selected_larger_node = false;
15304        let mut new_selections = old_selections
15305            .iter()
15306            .map(|selection| {
15307                let old_range = selection.start..selection.end;
15308
15309                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15310                    // manually select word at selection
15311                    if ["string_content", "inline"].contains(&node.kind()) {
15312                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15313                        // ignore if word is already selected
15314                        if !word_range.is_empty() && old_range != word_range {
15315                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15316                            // only select word if start and end point belongs to same word
15317                            if word_range == last_word_range {
15318                                selected_larger_node = true;
15319                                return Selection {
15320                                    id: selection.id,
15321                                    start: word_range.start,
15322                                    end: word_range.end,
15323                                    goal: SelectionGoal::None,
15324                                    reversed: selection.reversed,
15325                                };
15326                            }
15327                        }
15328                    }
15329                }
15330
15331                let mut new_range = old_range.clone();
15332                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15333                    new_range = range;
15334                    if !node.is_named() {
15335                        continue;
15336                    }
15337                    if !display_map.intersects_fold(new_range.start)
15338                        && !display_map.intersects_fold(new_range.end)
15339                    {
15340                        break;
15341                    }
15342                }
15343
15344                selected_larger_node |= new_range != old_range;
15345                Selection {
15346                    id: selection.id,
15347                    start: new_range.start,
15348                    end: new_range.end,
15349                    goal: SelectionGoal::None,
15350                    reversed: selection.reversed,
15351                }
15352            })
15353            .collect::<Vec<_>>();
15354
15355        if !selected_larger_node {
15356            return; // don't put this call in the history
15357        }
15358
15359        // scroll based on transformation done to the last selection created by the user
15360        let (last_old, last_new) = old_selections
15361            .last()
15362            .zip(new_selections.last().cloned())
15363            .expect("old_selections isn't empty");
15364
15365        // revert selection
15366        let is_selection_reversed = {
15367            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15368            new_selections.last_mut().expect("checked above").reversed =
15369                should_newest_selection_be_reversed;
15370            should_newest_selection_be_reversed
15371        };
15372
15373        if selected_larger_node {
15374            self.select_syntax_node_history.disable_clearing = true;
15375            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15376                s.select(new_selections.clone());
15377            });
15378            self.select_syntax_node_history.disable_clearing = false;
15379        }
15380
15381        let start_row = last_new.start.to_display_point(&display_map).row().0;
15382        let end_row = last_new.end.to_display_point(&display_map).row().0;
15383        let selection_height = end_row - start_row + 1;
15384        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15385
15386        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15387        let scroll_behavior = if fits_on_the_screen {
15388            self.request_autoscroll(Autoscroll::fit(), cx);
15389            SelectSyntaxNodeScrollBehavior::FitSelection
15390        } else if is_selection_reversed {
15391            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15392            SelectSyntaxNodeScrollBehavior::CursorTop
15393        } else {
15394            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15395            SelectSyntaxNodeScrollBehavior::CursorBottom
15396        };
15397
15398        self.select_syntax_node_history.push((
15399            old_selections,
15400            scroll_behavior,
15401            is_selection_reversed,
15402        ));
15403    }
15404
15405    pub fn select_smaller_syntax_node(
15406        &mut self,
15407        _: &SelectSmallerSyntaxNode,
15408        window: &mut Window,
15409        cx: &mut Context<Self>,
15410    ) {
15411        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15412
15413        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15414            self.select_syntax_node_history.pop()
15415        {
15416            if let Some(selection) = selections.last_mut() {
15417                selection.reversed = is_selection_reversed;
15418            }
15419
15420            self.select_syntax_node_history.disable_clearing = true;
15421            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15422                s.select(selections.to_vec());
15423            });
15424            self.select_syntax_node_history.disable_clearing = false;
15425
15426            match scroll_behavior {
15427                SelectSyntaxNodeScrollBehavior::CursorTop => {
15428                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15429                }
15430                SelectSyntaxNodeScrollBehavior::FitSelection => {
15431                    self.request_autoscroll(Autoscroll::fit(), cx);
15432                }
15433                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15434                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15435                }
15436            }
15437        }
15438    }
15439
15440    pub fn unwrap_syntax_node(
15441        &mut self,
15442        _: &UnwrapSyntaxNode,
15443        window: &mut Window,
15444        cx: &mut Context<Self>,
15445    ) {
15446        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15447
15448        let buffer = self.buffer.read(cx).snapshot(cx);
15449        let selections = self
15450            .selections
15451            .all::<usize>(&self.display_snapshot(cx))
15452            .into_iter()
15453            // subtracting the offset requires sorting
15454            .sorted_by_key(|i| i.start);
15455
15456        let full_edits = selections
15457            .into_iter()
15458            .filter_map(|selection| {
15459                let child = if selection.is_empty()
15460                    && let Some((_, ancestor_range)) =
15461                        buffer.syntax_ancestor(selection.start..selection.end)
15462                {
15463                    ancestor_range
15464                } else {
15465                    selection.range()
15466                };
15467
15468                let mut parent = child.clone();
15469                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15470                    parent = ancestor_range;
15471                    if parent.start < child.start || parent.end > child.end {
15472                        break;
15473                    }
15474                }
15475
15476                if parent == child {
15477                    return None;
15478                }
15479                let text = buffer.text_for_range(child).collect::<String>();
15480                Some((selection.id, parent, text))
15481            })
15482            .collect::<Vec<_>>();
15483        if full_edits.is_empty() {
15484            return;
15485        }
15486
15487        self.transact(window, cx, |this, window, cx| {
15488            this.buffer.update(cx, |buffer, cx| {
15489                buffer.edit(
15490                    full_edits
15491                        .iter()
15492                        .map(|(_, p, t)| (p.clone(), t.clone()))
15493                        .collect::<Vec<_>>(),
15494                    None,
15495                    cx,
15496                );
15497            });
15498            this.change_selections(Default::default(), window, cx, |s| {
15499                let mut offset = 0;
15500                let mut selections = vec![];
15501                for (id, parent, text) in full_edits {
15502                    let start = parent.start - offset;
15503                    offset += parent.len() - text.len();
15504                    selections.push(Selection {
15505                        id,
15506                        start,
15507                        end: start + text.len(),
15508                        reversed: false,
15509                        goal: Default::default(),
15510                    });
15511                }
15512                s.select(selections);
15513            });
15514        });
15515    }
15516
15517    pub fn select_next_syntax_node(
15518        &mut self,
15519        _: &SelectNextSyntaxNode,
15520        window: &mut Window,
15521        cx: &mut Context<Self>,
15522    ) {
15523        let old_selections: Box<[_]> = self
15524            .selections
15525            .all::<usize>(&self.display_snapshot(cx))
15526            .into();
15527        if old_selections.is_empty() {
15528            return;
15529        }
15530
15531        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15532
15533        let buffer = self.buffer.read(cx).snapshot(cx);
15534        let mut selected_sibling = false;
15535
15536        let new_selections = old_selections
15537            .iter()
15538            .map(|selection| {
15539                let old_range = selection.start..selection.end;
15540
15541                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15542                    let new_range = node.byte_range();
15543                    selected_sibling = true;
15544                    Selection {
15545                        id: selection.id,
15546                        start: new_range.start,
15547                        end: new_range.end,
15548                        goal: SelectionGoal::None,
15549                        reversed: selection.reversed,
15550                    }
15551                } else {
15552                    selection.clone()
15553                }
15554            })
15555            .collect::<Vec<_>>();
15556
15557        if selected_sibling {
15558            self.change_selections(
15559                SelectionEffects::scroll(Autoscroll::fit()),
15560                window,
15561                cx,
15562                |s| {
15563                    s.select(new_selections);
15564                },
15565            );
15566        }
15567    }
15568
15569    pub fn select_prev_syntax_node(
15570        &mut self,
15571        _: &SelectPreviousSyntaxNode,
15572        window: &mut Window,
15573        cx: &mut Context<Self>,
15574    ) {
15575        let old_selections: Box<[_]> = self
15576            .selections
15577            .all::<usize>(&self.display_snapshot(cx))
15578            .into();
15579        if old_selections.is_empty() {
15580            return;
15581        }
15582
15583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15584
15585        let buffer = self.buffer.read(cx).snapshot(cx);
15586        let mut selected_sibling = false;
15587
15588        let new_selections = old_selections
15589            .iter()
15590            .map(|selection| {
15591                let old_range = selection.start..selection.end;
15592
15593                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15594                    let new_range = node.byte_range();
15595                    selected_sibling = true;
15596                    Selection {
15597                        id: selection.id,
15598                        start: new_range.start,
15599                        end: new_range.end,
15600                        goal: SelectionGoal::None,
15601                        reversed: selection.reversed,
15602                    }
15603                } else {
15604                    selection.clone()
15605                }
15606            })
15607            .collect::<Vec<_>>();
15608
15609        if selected_sibling {
15610            self.change_selections(
15611                SelectionEffects::scroll(Autoscroll::fit()),
15612                window,
15613                cx,
15614                |s| {
15615                    s.select(new_selections);
15616                },
15617            );
15618        }
15619    }
15620
15621    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15622        if !EditorSettings::get_global(cx).gutter.runnables {
15623            self.clear_tasks();
15624            return Task::ready(());
15625        }
15626        let project = self.project().map(Entity::downgrade);
15627        let task_sources = self.lsp_task_sources(cx);
15628        let multi_buffer = self.buffer.downgrade();
15629        cx.spawn_in(window, async move |editor, cx| {
15630            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15631            let Some(project) = project.and_then(|p| p.upgrade()) else {
15632                return;
15633            };
15634            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15635                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15636            }) else {
15637                return;
15638            };
15639
15640            let hide_runnables = project
15641                .update(cx, |project, _| project.is_via_collab())
15642                .unwrap_or(true);
15643            if hide_runnables {
15644                return;
15645            }
15646            let new_rows =
15647                cx.background_spawn({
15648                    let snapshot = display_snapshot.clone();
15649                    async move {
15650                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15651                    }
15652                })
15653                    .await;
15654            let Ok(lsp_tasks) =
15655                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15656            else {
15657                return;
15658            };
15659            let lsp_tasks = lsp_tasks.await;
15660
15661            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15662                lsp_tasks
15663                    .into_iter()
15664                    .flat_map(|(kind, tasks)| {
15665                        tasks.into_iter().filter_map(move |(location, task)| {
15666                            Some((kind.clone(), location?, task))
15667                        })
15668                    })
15669                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15670                        let buffer = location.target.buffer;
15671                        let buffer_snapshot = buffer.read(cx).snapshot();
15672                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15673                            |(excerpt_id, snapshot, _)| {
15674                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15675                                    display_snapshot
15676                                        .buffer_snapshot()
15677                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15678                                } else {
15679                                    None
15680                                }
15681                            },
15682                        );
15683                        if let Some(offset) = offset {
15684                            let task_buffer_range =
15685                                location.target.range.to_point(&buffer_snapshot);
15686                            let context_buffer_range =
15687                                task_buffer_range.to_offset(&buffer_snapshot);
15688                            let context_range = BufferOffset(context_buffer_range.start)
15689                                ..BufferOffset(context_buffer_range.end);
15690
15691                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15692                                .or_insert_with(|| RunnableTasks {
15693                                    templates: Vec::new(),
15694                                    offset,
15695                                    column: task_buffer_range.start.column,
15696                                    extra_variables: HashMap::default(),
15697                                    context_range,
15698                                })
15699                                .templates
15700                                .push((kind, task.original_task().clone()));
15701                        }
15702
15703                        acc
15704                    })
15705            }) else {
15706                return;
15707            };
15708
15709            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15710                buffer.language_settings(cx).tasks.prefer_lsp
15711            }) else {
15712                return;
15713            };
15714
15715            let rows = Self::runnable_rows(
15716                project,
15717                display_snapshot,
15718                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15719                new_rows,
15720                cx.clone(),
15721            )
15722            .await;
15723            editor
15724                .update(cx, |editor, _| {
15725                    editor.clear_tasks();
15726                    for (key, mut value) in rows {
15727                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15728                            value.templates.extend(lsp_tasks.templates);
15729                        }
15730
15731                        editor.insert_tasks(key, value);
15732                    }
15733                    for (key, value) in lsp_tasks_by_rows {
15734                        editor.insert_tasks(key, value);
15735                    }
15736                })
15737                .ok();
15738        })
15739    }
15740    fn fetch_runnable_ranges(
15741        snapshot: &DisplaySnapshot,
15742        range: Range<Anchor>,
15743    ) -> Vec<language::RunnableRange> {
15744        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15745    }
15746
15747    fn runnable_rows(
15748        project: Entity<Project>,
15749        snapshot: DisplaySnapshot,
15750        prefer_lsp: bool,
15751        runnable_ranges: Vec<RunnableRange>,
15752        cx: AsyncWindowContext,
15753    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15754        cx.spawn(async move |cx| {
15755            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15756            for mut runnable in runnable_ranges {
15757                let Some(tasks) = cx
15758                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15759                    .ok()
15760                else {
15761                    continue;
15762                };
15763                let mut tasks = tasks.await;
15764
15765                if prefer_lsp {
15766                    tasks.retain(|(task_kind, _)| {
15767                        !matches!(task_kind, TaskSourceKind::Language { .. })
15768                    });
15769                }
15770                if tasks.is_empty() {
15771                    continue;
15772                }
15773
15774                let point = runnable
15775                    .run_range
15776                    .start
15777                    .to_point(&snapshot.buffer_snapshot());
15778                let Some(row) = snapshot
15779                    .buffer_snapshot()
15780                    .buffer_line_for_row(MultiBufferRow(point.row))
15781                    .map(|(_, range)| range.start.row)
15782                else {
15783                    continue;
15784                };
15785
15786                let context_range =
15787                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15788                runnable_rows.push((
15789                    (runnable.buffer_id, row),
15790                    RunnableTasks {
15791                        templates: tasks,
15792                        offset: snapshot
15793                            .buffer_snapshot()
15794                            .anchor_before(runnable.run_range.start),
15795                        context_range,
15796                        column: point.column,
15797                        extra_variables: runnable.extra_captures,
15798                    },
15799                ));
15800            }
15801            runnable_rows
15802        })
15803    }
15804
15805    fn templates_with_tags(
15806        project: &Entity<Project>,
15807        runnable: &mut Runnable,
15808        cx: &mut App,
15809    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15810        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15811            let (worktree_id, file) = project
15812                .buffer_for_id(runnable.buffer, cx)
15813                .and_then(|buffer| buffer.read(cx).file())
15814                .map(|file| (file.worktree_id(cx), file.clone()))
15815                .unzip();
15816
15817            (
15818                project.task_store().read(cx).task_inventory().cloned(),
15819                worktree_id,
15820                file,
15821            )
15822        });
15823
15824        let tags = mem::take(&mut runnable.tags);
15825        let language = runnable.language.clone();
15826        cx.spawn(async move |cx| {
15827            let mut templates_with_tags = Vec::new();
15828            if let Some(inventory) = inventory {
15829                for RunnableTag(tag) in tags {
15830                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15831                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15832                    }) else {
15833                        return templates_with_tags;
15834                    };
15835                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15836                        move |(_, template)| {
15837                            template.tags.iter().any(|source_tag| source_tag == &tag)
15838                        },
15839                    ));
15840                }
15841            }
15842            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15843
15844            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15845                // Strongest source wins; if we have worktree tag binding, prefer that to
15846                // global and language bindings;
15847                // if we have a global binding, prefer that to language binding.
15848                let first_mismatch = templates_with_tags
15849                    .iter()
15850                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15851                if let Some(index) = first_mismatch {
15852                    templates_with_tags.truncate(index);
15853                }
15854            }
15855
15856            templates_with_tags
15857        })
15858    }
15859
15860    pub fn move_to_enclosing_bracket(
15861        &mut self,
15862        _: &MoveToEnclosingBracket,
15863        window: &mut Window,
15864        cx: &mut Context<Self>,
15865    ) {
15866        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15867        self.change_selections(Default::default(), window, cx, |s| {
15868            s.move_offsets_with(|snapshot, selection| {
15869                let Some(enclosing_bracket_ranges) =
15870                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15871                else {
15872                    return;
15873                };
15874
15875                let mut best_length = usize::MAX;
15876                let mut best_inside = false;
15877                let mut best_in_bracket_range = false;
15878                let mut best_destination = None;
15879                for (open, close) in enclosing_bracket_ranges {
15880                    let close = close.to_inclusive();
15881                    let length = close.end() - open.start;
15882                    let inside = selection.start >= open.end && selection.end <= *close.start();
15883                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15884                        || close.contains(&selection.head());
15885
15886                    // If best is next to a bracket and current isn't, skip
15887                    if !in_bracket_range && best_in_bracket_range {
15888                        continue;
15889                    }
15890
15891                    // Prefer smaller lengths unless best is inside and current isn't
15892                    if length > best_length && (best_inside || !inside) {
15893                        continue;
15894                    }
15895
15896                    best_length = length;
15897                    best_inside = inside;
15898                    best_in_bracket_range = in_bracket_range;
15899                    best_destination = Some(
15900                        if close.contains(&selection.start) && close.contains(&selection.end) {
15901                            if inside { open.end } else { open.start }
15902                        } else if inside {
15903                            *close.start()
15904                        } else {
15905                            *close.end()
15906                        },
15907                    );
15908                }
15909
15910                if let Some(destination) = best_destination {
15911                    selection.collapse_to(destination, SelectionGoal::None);
15912                }
15913            })
15914        });
15915    }
15916
15917    pub fn undo_selection(
15918        &mut self,
15919        _: &UndoSelection,
15920        window: &mut Window,
15921        cx: &mut Context<Self>,
15922    ) {
15923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15924        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15925            self.selection_history.mode = SelectionHistoryMode::Undoing;
15926            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15927                this.end_selection(window, cx);
15928                this.change_selections(
15929                    SelectionEffects::scroll(Autoscroll::newest()),
15930                    window,
15931                    cx,
15932                    |s| s.select_anchors(entry.selections.to_vec()),
15933                );
15934            });
15935            self.selection_history.mode = SelectionHistoryMode::Normal;
15936
15937            self.select_next_state = entry.select_next_state;
15938            self.select_prev_state = entry.select_prev_state;
15939            self.add_selections_state = entry.add_selections_state;
15940        }
15941    }
15942
15943    pub fn redo_selection(
15944        &mut self,
15945        _: &RedoSelection,
15946        window: &mut Window,
15947        cx: &mut Context<Self>,
15948    ) {
15949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15950        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15951            self.selection_history.mode = SelectionHistoryMode::Redoing;
15952            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15953                this.end_selection(window, cx);
15954                this.change_selections(
15955                    SelectionEffects::scroll(Autoscroll::newest()),
15956                    window,
15957                    cx,
15958                    |s| s.select_anchors(entry.selections.to_vec()),
15959                );
15960            });
15961            self.selection_history.mode = SelectionHistoryMode::Normal;
15962
15963            self.select_next_state = entry.select_next_state;
15964            self.select_prev_state = entry.select_prev_state;
15965            self.add_selections_state = entry.add_selections_state;
15966        }
15967    }
15968
15969    pub fn expand_excerpts(
15970        &mut self,
15971        action: &ExpandExcerpts,
15972        _: &mut Window,
15973        cx: &mut Context<Self>,
15974    ) {
15975        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15976    }
15977
15978    pub fn expand_excerpts_down(
15979        &mut self,
15980        action: &ExpandExcerptsDown,
15981        _: &mut Window,
15982        cx: &mut Context<Self>,
15983    ) {
15984        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15985    }
15986
15987    pub fn expand_excerpts_up(
15988        &mut self,
15989        action: &ExpandExcerptsUp,
15990        _: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15994    }
15995
15996    pub fn expand_excerpts_for_direction(
15997        &mut self,
15998        lines: u32,
15999        direction: ExpandExcerptDirection,
16000
16001        cx: &mut Context<Self>,
16002    ) {
16003        let selections = self.selections.disjoint_anchors_arc();
16004
16005        let lines = if lines == 0 {
16006            EditorSettings::get_global(cx).expand_excerpt_lines
16007        } else {
16008            lines
16009        };
16010
16011        self.buffer.update(cx, |buffer, cx| {
16012            let snapshot = buffer.snapshot(cx);
16013            let mut excerpt_ids = selections
16014                .iter()
16015                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16016                .collect::<Vec<_>>();
16017            excerpt_ids.sort();
16018            excerpt_ids.dedup();
16019            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16020        })
16021    }
16022
16023    pub fn expand_excerpt(
16024        &mut self,
16025        excerpt: ExcerptId,
16026        direction: ExpandExcerptDirection,
16027        window: &mut Window,
16028        cx: &mut Context<Self>,
16029    ) {
16030        let current_scroll_position = self.scroll_position(cx);
16031        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16032        let mut should_scroll_up = false;
16033
16034        if direction == ExpandExcerptDirection::Down {
16035            let multi_buffer = self.buffer.read(cx);
16036            let snapshot = multi_buffer.snapshot(cx);
16037            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16038                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16039                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16040            {
16041                let buffer_snapshot = buffer.read(cx).snapshot();
16042                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16043                let last_row = buffer_snapshot.max_point().row;
16044                let lines_below = last_row.saturating_sub(excerpt_end_row);
16045                should_scroll_up = lines_below >= lines_to_expand;
16046            }
16047        }
16048
16049        self.buffer.update(cx, |buffer, cx| {
16050            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16051        });
16052
16053        if should_scroll_up {
16054            let new_scroll_position =
16055                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
16056            self.set_scroll_position(new_scroll_position, window, cx);
16057        }
16058    }
16059
16060    pub fn go_to_singleton_buffer_point(
16061        &mut self,
16062        point: Point,
16063        window: &mut Window,
16064        cx: &mut Context<Self>,
16065    ) {
16066        self.go_to_singleton_buffer_range(point..point, window, cx);
16067    }
16068
16069    pub fn go_to_singleton_buffer_range(
16070        &mut self,
16071        range: Range<Point>,
16072        window: &mut Window,
16073        cx: &mut Context<Self>,
16074    ) {
16075        let multibuffer = self.buffer().read(cx);
16076        let Some(buffer) = multibuffer.as_singleton() else {
16077            return;
16078        };
16079        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16080            return;
16081        };
16082        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16083            return;
16084        };
16085        self.change_selections(
16086            SelectionEffects::default().nav_history(true),
16087            window,
16088            cx,
16089            |s| s.select_anchor_ranges([start..end]),
16090        );
16091    }
16092
16093    pub fn go_to_diagnostic(
16094        &mut self,
16095        action: &GoToDiagnostic,
16096        window: &mut Window,
16097        cx: &mut Context<Self>,
16098    ) {
16099        if !self.diagnostics_enabled() {
16100            return;
16101        }
16102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16103        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16104    }
16105
16106    pub fn go_to_prev_diagnostic(
16107        &mut self,
16108        action: &GoToPreviousDiagnostic,
16109        window: &mut Window,
16110        cx: &mut Context<Self>,
16111    ) {
16112        if !self.diagnostics_enabled() {
16113            return;
16114        }
16115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16116        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16117    }
16118
16119    pub fn go_to_diagnostic_impl(
16120        &mut self,
16121        direction: Direction,
16122        severity: GoToDiagnosticSeverityFilter,
16123        window: &mut Window,
16124        cx: &mut Context<Self>,
16125    ) {
16126        let buffer = self.buffer.read(cx).snapshot(cx);
16127        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16128
16129        let mut active_group_id = None;
16130        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16131            && active_group.active_range.start.to_offset(&buffer) == selection.start
16132        {
16133            active_group_id = Some(active_group.group_id);
16134        }
16135
16136        fn filtered<'a>(
16137            snapshot: EditorSnapshot,
16138            severity: GoToDiagnosticSeverityFilter,
16139            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16140        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16141            diagnostics
16142                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16143                .filter(|entry| entry.range.start != entry.range.end)
16144                .filter(|entry| !entry.diagnostic.is_unnecessary)
16145                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16146        }
16147
16148        let snapshot = self.snapshot(window, cx);
16149        let before = filtered(
16150            snapshot.clone(),
16151            severity,
16152            buffer
16153                .diagnostics_in_range(0..selection.start)
16154                .filter(|entry| entry.range.start <= selection.start),
16155        );
16156        let after = filtered(
16157            snapshot,
16158            severity,
16159            buffer
16160                .diagnostics_in_range(selection.start..buffer.len())
16161                .filter(|entry| entry.range.start >= selection.start),
16162        );
16163
16164        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16165        if direction == Direction::Prev {
16166            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16167            {
16168                for diagnostic in prev_diagnostics.into_iter().rev() {
16169                    if diagnostic.range.start != selection.start
16170                        || active_group_id
16171                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16172                    {
16173                        found = Some(diagnostic);
16174                        break 'outer;
16175                    }
16176                }
16177            }
16178        } else {
16179            for diagnostic in after.chain(before) {
16180                if diagnostic.range.start != selection.start
16181                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16182                {
16183                    found = Some(diagnostic);
16184                    break;
16185                }
16186            }
16187        }
16188        let Some(next_diagnostic) = found else {
16189            return;
16190        };
16191
16192        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16193        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16194            return;
16195        };
16196        self.change_selections(Default::default(), window, cx, |s| {
16197            s.select_ranges(vec![
16198                next_diagnostic.range.start..next_diagnostic.range.start,
16199            ])
16200        });
16201        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16202        self.refresh_edit_prediction(false, true, window, cx);
16203    }
16204
16205    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16207        let snapshot = self.snapshot(window, cx);
16208        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16209        self.go_to_hunk_before_or_after_position(
16210            &snapshot,
16211            selection.head(),
16212            Direction::Next,
16213            window,
16214            cx,
16215        );
16216    }
16217
16218    pub fn go_to_hunk_before_or_after_position(
16219        &mut self,
16220        snapshot: &EditorSnapshot,
16221        position: Point,
16222        direction: Direction,
16223        window: &mut Window,
16224        cx: &mut Context<Editor>,
16225    ) {
16226        let row = if direction == Direction::Next {
16227            self.hunk_after_position(snapshot, position)
16228                .map(|hunk| hunk.row_range.start)
16229        } else {
16230            self.hunk_before_position(snapshot, position)
16231        };
16232
16233        if let Some(row) = row {
16234            let destination = Point::new(row.0, 0);
16235            let autoscroll = Autoscroll::center();
16236
16237            self.unfold_ranges(&[destination..destination], false, false, cx);
16238            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16239                s.select_ranges([destination..destination]);
16240            });
16241        }
16242    }
16243
16244    fn hunk_after_position(
16245        &mut self,
16246        snapshot: &EditorSnapshot,
16247        position: Point,
16248    ) -> Option<MultiBufferDiffHunk> {
16249        snapshot
16250            .buffer_snapshot()
16251            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16252            .find(|hunk| hunk.row_range.start.0 > position.row)
16253            .or_else(|| {
16254                snapshot
16255                    .buffer_snapshot()
16256                    .diff_hunks_in_range(Point::zero()..position)
16257                    .find(|hunk| hunk.row_range.end.0 < position.row)
16258            })
16259    }
16260
16261    fn go_to_prev_hunk(
16262        &mut self,
16263        _: &GoToPreviousHunk,
16264        window: &mut Window,
16265        cx: &mut Context<Self>,
16266    ) {
16267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16268        let snapshot = self.snapshot(window, cx);
16269        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16270        self.go_to_hunk_before_or_after_position(
16271            &snapshot,
16272            selection.head(),
16273            Direction::Prev,
16274            window,
16275            cx,
16276        );
16277    }
16278
16279    fn hunk_before_position(
16280        &mut self,
16281        snapshot: &EditorSnapshot,
16282        position: Point,
16283    ) -> Option<MultiBufferRow> {
16284        snapshot
16285            .buffer_snapshot()
16286            .diff_hunk_before(position)
16287            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16288    }
16289
16290    fn go_to_next_change(
16291        &mut self,
16292        _: &GoToNextChange,
16293        window: &mut Window,
16294        cx: &mut Context<Self>,
16295    ) {
16296        if let Some(selections) = self
16297            .change_list
16298            .next_change(1, Direction::Next)
16299            .map(|s| s.to_vec())
16300        {
16301            self.change_selections(Default::default(), window, cx, |s| {
16302                let map = s.display_map();
16303                s.select_display_ranges(selections.iter().map(|a| {
16304                    let point = a.to_display_point(&map);
16305                    point..point
16306                }))
16307            })
16308        }
16309    }
16310
16311    fn go_to_previous_change(
16312        &mut self,
16313        _: &GoToPreviousChange,
16314        window: &mut Window,
16315        cx: &mut Context<Self>,
16316    ) {
16317        if let Some(selections) = self
16318            .change_list
16319            .next_change(1, Direction::Prev)
16320            .map(|s| s.to_vec())
16321        {
16322            self.change_selections(Default::default(), window, cx, |s| {
16323                let map = s.display_map();
16324                s.select_display_ranges(selections.iter().map(|a| {
16325                    let point = a.to_display_point(&map);
16326                    point..point
16327                }))
16328            })
16329        }
16330    }
16331
16332    pub fn go_to_next_document_highlight(
16333        &mut self,
16334        _: &GoToNextDocumentHighlight,
16335        window: &mut Window,
16336        cx: &mut Context<Self>,
16337    ) {
16338        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16339    }
16340
16341    pub fn go_to_prev_document_highlight(
16342        &mut self,
16343        _: &GoToPreviousDocumentHighlight,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16348    }
16349
16350    pub fn go_to_document_highlight_before_or_after_position(
16351        &mut self,
16352        direction: Direction,
16353        window: &mut Window,
16354        cx: &mut Context<Editor>,
16355    ) {
16356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16357        let snapshot = self.snapshot(window, cx);
16358        let buffer = &snapshot.buffer_snapshot();
16359        let position = self
16360            .selections
16361            .newest::<Point>(&snapshot.display_snapshot)
16362            .head();
16363        let anchor_position = buffer.anchor_after(position);
16364
16365        // Get all document highlights (both read and write)
16366        let mut all_highlights = Vec::new();
16367
16368        if let Some((_, read_highlights)) = self
16369            .background_highlights
16370            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16371        {
16372            all_highlights.extend(read_highlights.iter());
16373        }
16374
16375        if let Some((_, write_highlights)) = self
16376            .background_highlights
16377            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16378        {
16379            all_highlights.extend(write_highlights.iter());
16380        }
16381
16382        if all_highlights.is_empty() {
16383            return;
16384        }
16385
16386        // Sort highlights by position
16387        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16388
16389        let target_highlight = match direction {
16390            Direction::Next => {
16391                // Find the first highlight after the current position
16392                all_highlights
16393                    .iter()
16394                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16395            }
16396            Direction::Prev => {
16397                // Find the last highlight before the current position
16398                all_highlights
16399                    .iter()
16400                    .rev()
16401                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16402            }
16403        };
16404
16405        if let Some(highlight) = target_highlight {
16406            let destination = highlight.start.to_point(buffer);
16407            let autoscroll = Autoscroll::center();
16408
16409            self.unfold_ranges(&[destination..destination], false, false, cx);
16410            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16411                s.select_ranges([destination..destination]);
16412            });
16413        }
16414    }
16415
16416    fn go_to_line<T: 'static>(
16417        &mut self,
16418        position: Anchor,
16419        highlight_color: Option<Hsla>,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) {
16423        let snapshot = self.snapshot(window, cx).display_snapshot;
16424        let position = position.to_point(&snapshot.buffer_snapshot());
16425        let start = snapshot
16426            .buffer_snapshot()
16427            .clip_point(Point::new(position.row, 0), Bias::Left);
16428        let end = start + Point::new(1, 0);
16429        let start = snapshot.buffer_snapshot().anchor_before(start);
16430        let end = snapshot.buffer_snapshot().anchor_before(end);
16431
16432        self.highlight_rows::<T>(
16433            start..end,
16434            highlight_color
16435                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16436            Default::default(),
16437            cx,
16438        );
16439
16440        if self.buffer.read(cx).is_singleton() {
16441            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16442        }
16443    }
16444
16445    pub fn go_to_definition(
16446        &mut self,
16447        _: &GoToDefinition,
16448        window: &mut Window,
16449        cx: &mut Context<Self>,
16450    ) -> Task<Result<Navigated>> {
16451        let definition =
16452            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16453        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16454        cx.spawn_in(window, async move |editor, cx| {
16455            if definition.await? == Navigated::Yes {
16456                return Ok(Navigated::Yes);
16457            }
16458            match fallback_strategy {
16459                GoToDefinitionFallback::None => Ok(Navigated::No),
16460                GoToDefinitionFallback::FindAllReferences => {
16461                    match editor.update_in(cx, |editor, window, cx| {
16462                        editor.find_all_references(&FindAllReferences, window, cx)
16463                    })? {
16464                        Some(references) => references.await,
16465                        None => Ok(Navigated::No),
16466                    }
16467                }
16468            }
16469        })
16470    }
16471
16472    pub fn go_to_declaration(
16473        &mut self,
16474        _: &GoToDeclaration,
16475        window: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) -> Task<Result<Navigated>> {
16478        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16479    }
16480
16481    pub fn go_to_declaration_split(
16482        &mut self,
16483        _: &GoToDeclaration,
16484        window: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) -> Task<Result<Navigated>> {
16487        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16488    }
16489
16490    pub fn go_to_implementation(
16491        &mut self,
16492        _: &GoToImplementation,
16493        window: &mut Window,
16494        cx: &mut Context<Self>,
16495    ) -> Task<Result<Navigated>> {
16496        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16497    }
16498
16499    pub fn go_to_implementation_split(
16500        &mut self,
16501        _: &GoToImplementationSplit,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) -> Task<Result<Navigated>> {
16505        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16506    }
16507
16508    pub fn go_to_type_definition(
16509        &mut self,
16510        _: &GoToTypeDefinition,
16511        window: &mut Window,
16512        cx: &mut Context<Self>,
16513    ) -> Task<Result<Navigated>> {
16514        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16515    }
16516
16517    pub fn go_to_definition_split(
16518        &mut self,
16519        _: &GoToDefinitionSplit,
16520        window: &mut Window,
16521        cx: &mut Context<Self>,
16522    ) -> Task<Result<Navigated>> {
16523        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16524    }
16525
16526    pub fn go_to_type_definition_split(
16527        &mut self,
16528        _: &GoToTypeDefinitionSplit,
16529        window: &mut Window,
16530        cx: &mut Context<Self>,
16531    ) -> Task<Result<Navigated>> {
16532        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16533    }
16534
16535    fn go_to_definition_of_kind(
16536        &mut self,
16537        kind: GotoDefinitionKind,
16538        split: bool,
16539        window: &mut Window,
16540        cx: &mut Context<Self>,
16541    ) -> Task<Result<Navigated>> {
16542        let Some(provider) = self.semantics_provider.clone() else {
16543            return Task::ready(Ok(Navigated::No));
16544        };
16545        let head = self
16546            .selections
16547            .newest::<usize>(&self.display_snapshot(cx))
16548            .head();
16549        let buffer = self.buffer.read(cx);
16550        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16551            return Task::ready(Ok(Navigated::No));
16552        };
16553        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16554            return Task::ready(Ok(Navigated::No));
16555        };
16556
16557        cx.spawn_in(window, async move |editor, cx| {
16558            let Some(definitions) = definitions.await? else {
16559                return Ok(Navigated::No);
16560            };
16561            let navigated = editor
16562                .update_in(cx, |editor, window, cx| {
16563                    editor.navigate_to_hover_links(
16564                        Some(kind),
16565                        definitions
16566                            .into_iter()
16567                            .filter(|location| {
16568                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16569                            })
16570                            .map(HoverLink::Text)
16571                            .collect::<Vec<_>>(),
16572                        split,
16573                        window,
16574                        cx,
16575                    )
16576                })?
16577                .await?;
16578            anyhow::Ok(navigated)
16579        })
16580    }
16581
16582    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16583        let selection = self.selections.newest_anchor();
16584        let head = selection.head();
16585        let tail = selection.tail();
16586
16587        let Some((buffer, start_position)) =
16588            self.buffer.read(cx).text_anchor_for_position(head, cx)
16589        else {
16590            return;
16591        };
16592
16593        let end_position = if head != tail {
16594            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16595                return;
16596            };
16597            Some(pos)
16598        } else {
16599            None
16600        };
16601
16602        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16603            let url = if let Some(end_pos) = end_position {
16604                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16605            } else {
16606                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16607            };
16608
16609            if let Some(url) = url {
16610                cx.update(|window, cx| {
16611                    if parse_zed_link(&url, cx).is_some() {
16612                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16613                    } else {
16614                        cx.open_url(&url);
16615                    }
16616                })?;
16617            }
16618
16619            anyhow::Ok(())
16620        });
16621
16622        url_finder.detach();
16623    }
16624
16625    pub fn open_selected_filename(
16626        &mut self,
16627        _: &OpenSelectedFilename,
16628        window: &mut Window,
16629        cx: &mut Context<Self>,
16630    ) {
16631        let Some(workspace) = self.workspace() else {
16632            return;
16633        };
16634
16635        let position = self.selections.newest_anchor().head();
16636
16637        let Some((buffer, buffer_position)) =
16638            self.buffer.read(cx).text_anchor_for_position(position, cx)
16639        else {
16640            return;
16641        };
16642
16643        let project = self.project.clone();
16644
16645        cx.spawn_in(window, async move |_, cx| {
16646            let result = find_file(&buffer, project, buffer_position, cx).await;
16647
16648            if let Some((_, path)) = result {
16649                workspace
16650                    .update_in(cx, |workspace, window, cx| {
16651                        workspace.open_resolved_path(path, window, cx)
16652                    })?
16653                    .await?;
16654            }
16655            anyhow::Ok(())
16656        })
16657        .detach();
16658    }
16659
16660    pub(crate) fn navigate_to_hover_links(
16661        &mut self,
16662        kind: Option<GotoDefinitionKind>,
16663        definitions: Vec<HoverLink>,
16664        split: bool,
16665        window: &mut Window,
16666        cx: &mut Context<Editor>,
16667    ) -> Task<Result<Navigated>> {
16668        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16669        let mut first_url_or_file = None;
16670        let definitions: Vec<_> = definitions
16671            .into_iter()
16672            .filter_map(|def| match def {
16673                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16674                HoverLink::InlayHint(lsp_location, server_id) => {
16675                    let computation =
16676                        self.compute_target_location(lsp_location, server_id, window, cx);
16677                    Some(cx.background_spawn(computation))
16678                }
16679                HoverLink::Url(url) => {
16680                    first_url_or_file = Some(Either::Left(url));
16681                    None
16682                }
16683                HoverLink::File(path) => {
16684                    first_url_or_file = Some(Either::Right(path));
16685                    None
16686                }
16687            })
16688            .collect();
16689
16690        let workspace = self.workspace();
16691
16692        cx.spawn_in(window, async move |editor, cx| {
16693            let locations: Vec<Location> = future::join_all(definitions)
16694                .await
16695                .into_iter()
16696                .filter_map(|location| location.transpose())
16697                .collect::<Result<_>>()
16698                .context("location tasks")?;
16699            let mut locations = cx.update(|_, cx| {
16700                locations
16701                    .into_iter()
16702                    .map(|location| {
16703                        let buffer = location.buffer.read(cx);
16704                        (location.buffer, location.range.to_point(buffer))
16705                    })
16706                    .into_group_map()
16707            })?;
16708            let mut num_locations = 0;
16709            for ranges in locations.values_mut() {
16710                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16711                ranges.dedup();
16712                num_locations += ranges.len();
16713            }
16714
16715            if num_locations > 1 {
16716                let Some(workspace) = workspace else {
16717                    return Ok(Navigated::No);
16718                };
16719
16720                let tab_kind = match kind {
16721                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16722                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16723                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16724                    Some(GotoDefinitionKind::Type) => "Types",
16725                };
16726                let title = editor
16727                    .update_in(cx, |_, _, cx| {
16728                        let target = locations
16729                            .iter()
16730                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16731                            .map(|(buffer, location)| {
16732                                buffer
16733                                    .read(cx)
16734                                    .text_for_range(location.clone())
16735                                    .collect::<String>()
16736                            })
16737                            .filter(|text| !text.contains('\n'))
16738                            .unique()
16739                            .take(3)
16740                            .join(", ");
16741                        if target.is_empty() {
16742                            tab_kind.to_owned()
16743                        } else {
16744                            format!("{tab_kind} for {target}")
16745                        }
16746                    })
16747                    .context("buffer title")?;
16748
16749                let opened = workspace
16750                    .update_in(cx, |workspace, window, cx| {
16751                        Self::open_locations_in_multibuffer(
16752                            workspace,
16753                            locations,
16754                            title,
16755                            split,
16756                            MultibufferSelectionMode::First,
16757                            window,
16758                            cx,
16759                        )
16760                    })
16761                    .is_ok();
16762
16763                anyhow::Ok(Navigated::from_bool(opened))
16764            } else if num_locations == 0 {
16765                // If there is one url or file, open it directly
16766                match first_url_or_file {
16767                    Some(Either::Left(url)) => {
16768                        cx.update(|_, cx| cx.open_url(&url))?;
16769                        Ok(Navigated::Yes)
16770                    }
16771                    Some(Either::Right(path)) => {
16772                        let Some(workspace) = workspace else {
16773                            return Ok(Navigated::No);
16774                        };
16775
16776                        workspace
16777                            .update_in(cx, |workspace, window, cx| {
16778                                workspace.open_resolved_path(path, window, cx)
16779                            })?
16780                            .await?;
16781                        Ok(Navigated::Yes)
16782                    }
16783                    None => Ok(Navigated::No),
16784                }
16785            } else {
16786                let Some(workspace) = workspace else {
16787                    return Ok(Navigated::No);
16788                };
16789
16790                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16791                let target_range = target_ranges.first().unwrap().clone();
16792
16793                editor.update_in(cx, |editor, window, cx| {
16794                    let range = target_range.to_point(target_buffer.read(cx));
16795                    let range = editor.range_for_match(&range);
16796                    let range = collapse_multiline_range(range);
16797
16798                    if !split
16799                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16800                    {
16801                        editor.go_to_singleton_buffer_range(range, window, cx);
16802                    } else {
16803                        let pane = workspace.read(cx).active_pane().clone();
16804                        window.defer(cx, move |window, cx| {
16805                            let target_editor: Entity<Self> =
16806                                workspace.update(cx, |workspace, cx| {
16807                                    let pane = if split {
16808                                        workspace.adjacent_pane(window, cx)
16809                                    } else {
16810                                        workspace.active_pane().clone()
16811                                    };
16812
16813                                    workspace.open_project_item(
16814                                        pane,
16815                                        target_buffer.clone(),
16816                                        true,
16817                                        true,
16818                                        window,
16819                                        cx,
16820                                    )
16821                                });
16822                            target_editor.update(cx, |target_editor, cx| {
16823                                // When selecting a definition in a different buffer, disable the nav history
16824                                // to avoid creating a history entry at the previous cursor location.
16825                                pane.update(cx, |pane, _| pane.disable_history());
16826                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16827                                pane.update(cx, |pane, _| pane.enable_history());
16828                            });
16829                        });
16830                    }
16831                    Navigated::Yes
16832                })
16833            }
16834        })
16835    }
16836
16837    fn compute_target_location(
16838        &self,
16839        lsp_location: lsp::Location,
16840        server_id: LanguageServerId,
16841        window: &mut Window,
16842        cx: &mut Context<Self>,
16843    ) -> Task<anyhow::Result<Option<Location>>> {
16844        let Some(project) = self.project.clone() else {
16845            return Task::ready(Ok(None));
16846        };
16847
16848        cx.spawn_in(window, async move |editor, cx| {
16849            let location_task = editor.update(cx, |_, cx| {
16850                project.update(cx, |project, cx| {
16851                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16852                })
16853            })?;
16854            let location = Some({
16855                let target_buffer_handle = location_task.await.context("open local buffer")?;
16856                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16857                    let target_start = target_buffer
16858                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16859                    let target_end = target_buffer
16860                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16861                    target_buffer.anchor_after(target_start)
16862                        ..target_buffer.anchor_before(target_end)
16863                })?;
16864                Location {
16865                    buffer: target_buffer_handle,
16866                    range,
16867                }
16868            });
16869            Ok(location)
16870        })
16871    }
16872
16873    pub fn find_all_references(
16874        &mut self,
16875        _: &FindAllReferences,
16876        window: &mut Window,
16877        cx: &mut Context<Self>,
16878    ) -> Option<Task<Result<Navigated>>> {
16879        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16880        let multi_buffer = self.buffer.read(cx);
16881        let head = selection.head();
16882
16883        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16884        let head_anchor = multi_buffer_snapshot.anchor_at(
16885            head,
16886            if head < selection.tail() {
16887                Bias::Right
16888            } else {
16889                Bias::Left
16890            },
16891        );
16892
16893        match self
16894            .find_all_references_task_sources
16895            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16896        {
16897            Ok(_) => {
16898                log::info!(
16899                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16900                );
16901                return None;
16902            }
16903            Err(i) => {
16904                self.find_all_references_task_sources.insert(i, head_anchor);
16905            }
16906        }
16907
16908        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16909        let workspace = self.workspace()?;
16910        let project = workspace.read(cx).project().clone();
16911        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16912        Some(cx.spawn_in(window, async move |editor, cx| {
16913            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16914                if let Ok(i) = editor
16915                    .find_all_references_task_sources
16916                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16917                {
16918                    editor.find_all_references_task_sources.remove(i);
16919                }
16920            });
16921
16922            let Some(locations) = references.await? else {
16923                return anyhow::Ok(Navigated::No);
16924            };
16925            let mut locations = cx.update(|_, cx| {
16926                locations
16927                    .into_iter()
16928                    .map(|location| {
16929                        let buffer = location.buffer.read(cx);
16930                        (location.buffer, location.range.to_point(buffer))
16931                    })
16932                    .into_group_map()
16933            })?;
16934            if locations.is_empty() {
16935                return anyhow::Ok(Navigated::No);
16936            }
16937            for ranges in locations.values_mut() {
16938                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16939                ranges.dedup();
16940            }
16941
16942            workspace.update_in(cx, |workspace, window, cx| {
16943                let target = locations
16944                    .iter()
16945                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16946                    .map(|(buffer, location)| {
16947                        buffer
16948                            .read(cx)
16949                            .text_for_range(location.clone())
16950                            .collect::<String>()
16951                    })
16952                    .filter(|text| !text.contains('\n'))
16953                    .unique()
16954                    .take(3)
16955                    .join(", ");
16956                let title = if target.is_empty() {
16957                    "References".to_owned()
16958                } else {
16959                    format!("References to {target}")
16960                };
16961                Self::open_locations_in_multibuffer(
16962                    workspace,
16963                    locations,
16964                    title,
16965                    false,
16966                    MultibufferSelectionMode::First,
16967                    window,
16968                    cx,
16969                );
16970                Navigated::Yes
16971            })
16972        }))
16973    }
16974
16975    /// Opens a multibuffer with the given project locations in it
16976    pub fn open_locations_in_multibuffer(
16977        workspace: &mut Workspace,
16978        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16979        title: String,
16980        split: bool,
16981        multibuffer_selection_mode: MultibufferSelectionMode,
16982        window: &mut Window,
16983        cx: &mut Context<Workspace>,
16984    ) {
16985        if locations.is_empty() {
16986            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16987            return;
16988        }
16989
16990        let capability = workspace.project().read(cx).capability();
16991        let mut ranges = <Vec<Range<Anchor>>>::new();
16992
16993        // a key to find existing multibuffer editors with the same set of locations
16994        // to prevent us from opening more and more multibuffer tabs for searches and the like
16995        let mut key = (title.clone(), vec![]);
16996        let excerpt_buffer = cx.new(|cx| {
16997            let key = &mut key.1;
16998            let mut multibuffer = MultiBuffer::new(capability);
16999            for (buffer, mut ranges_for_buffer) in locations {
17000                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17001                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17002                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17003                    PathKey::for_buffer(&buffer, cx),
17004                    buffer.clone(),
17005                    ranges_for_buffer,
17006                    multibuffer_context_lines(cx),
17007                    cx,
17008                );
17009                ranges.extend(new_ranges)
17010            }
17011
17012            multibuffer.with_title(title)
17013        });
17014        let existing = workspace.active_pane().update(cx, |pane, cx| {
17015            pane.items()
17016                .filter_map(|item| item.downcast::<Editor>())
17017                .find(|editor| {
17018                    editor
17019                        .read(cx)
17020                        .lookup_key
17021                        .as_ref()
17022                        .and_then(|it| {
17023                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17024                        })
17025                        .is_some_and(|it| *it == key)
17026                })
17027        });
17028        let editor = existing.unwrap_or_else(|| {
17029            cx.new(|cx| {
17030                let mut editor = Editor::for_multibuffer(
17031                    excerpt_buffer,
17032                    Some(workspace.project().clone()),
17033                    window,
17034                    cx,
17035                );
17036                editor.lookup_key = Some(Box::new(key));
17037                editor
17038            })
17039        });
17040        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17041            MultibufferSelectionMode::First => {
17042                if let Some(first_range) = ranges.first() {
17043                    editor.change_selections(
17044                        SelectionEffects::no_scroll(),
17045                        window,
17046                        cx,
17047                        |selections| {
17048                            selections.clear_disjoint();
17049                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17050                        },
17051                    );
17052                }
17053                editor.highlight_background::<Self>(
17054                    &ranges,
17055                    |theme| theme.colors().editor_highlighted_line_background,
17056                    cx,
17057                );
17058            }
17059            MultibufferSelectionMode::All => {
17060                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17061                    selections.clear_disjoint();
17062                    selections.select_anchor_ranges(ranges);
17063                });
17064            }
17065        });
17066
17067        let item = Box::new(editor);
17068        let item_id = item.item_id();
17069
17070        if split {
17071            let pane = workspace.adjacent_pane(window, cx);
17072            workspace.add_item(pane, item, None, true, true, window, cx);
17073        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17074            let (preview_item_id, preview_item_idx) =
17075                workspace.active_pane().read_with(cx, |pane, _| {
17076                    (pane.preview_item_id(), pane.preview_item_idx())
17077                });
17078
17079            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17080
17081            if let Some(preview_item_id) = preview_item_id {
17082                workspace.active_pane().update(cx, |pane, cx| {
17083                    pane.remove_item(preview_item_id, false, false, window, cx);
17084                });
17085            }
17086        } else {
17087            workspace.add_item_to_active_pane(item, None, true, window, cx);
17088        }
17089        workspace.active_pane().update(cx, |pane, cx| {
17090            pane.set_preview_item_id(Some(item_id), cx);
17091        });
17092    }
17093
17094    pub fn rename(
17095        &mut self,
17096        _: &Rename,
17097        window: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) -> Option<Task<Result<()>>> {
17100        use language::ToOffset as _;
17101
17102        let provider = self.semantics_provider.clone()?;
17103        let selection = self.selections.newest_anchor().clone();
17104        let (cursor_buffer, cursor_buffer_position) = self
17105            .buffer
17106            .read(cx)
17107            .text_anchor_for_position(selection.head(), cx)?;
17108        let (tail_buffer, cursor_buffer_position_end) = self
17109            .buffer
17110            .read(cx)
17111            .text_anchor_for_position(selection.tail(), cx)?;
17112        if tail_buffer != cursor_buffer {
17113            return None;
17114        }
17115
17116        let snapshot = cursor_buffer.read(cx).snapshot();
17117        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17118        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17119        let prepare_rename = provider
17120            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17121            .unwrap_or_else(|| Task::ready(Ok(None)));
17122        drop(snapshot);
17123
17124        Some(cx.spawn_in(window, async move |this, cx| {
17125            let rename_range = if let Some(range) = prepare_rename.await? {
17126                Some(range)
17127            } else {
17128                this.update(cx, |this, cx| {
17129                    let buffer = this.buffer.read(cx).snapshot(cx);
17130                    let mut buffer_highlights = this
17131                        .document_highlights_for_position(selection.head(), &buffer)
17132                        .filter(|highlight| {
17133                            highlight.start.excerpt_id == selection.head().excerpt_id
17134                                && highlight.end.excerpt_id == selection.head().excerpt_id
17135                        });
17136                    buffer_highlights
17137                        .next()
17138                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17139                })?
17140            };
17141            if let Some(rename_range) = rename_range {
17142                this.update_in(cx, |this, window, cx| {
17143                    let snapshot = cursor_buffer.read(cx).snapshot();
17144                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17145                    let cursor_offset_in_rename_range =
17146                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17147                    let cursor_offset_in_rename_range_end =
17148                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17149
17150                    this.take_rename(false, window, cx);
17151                    let buffer = this.buffer.read(cx).read(cx);
17152                    let cursor_offset = selection.head().to_offset(&buffer);
17153                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17154                    let rename_end = rename_start + rename_buffer_range.len();
17155                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17156                    let mut old_highlight_id = None;
17157                    let old_name: Arc<str> = buffer
17158                        .chunks(rename_start..rename_end, true)
17159                        .map(|chunk| {
17160                            if old_highlight_id.is_none() {
17161                                old_highlight_id = chunk.syntax_highlight_id;
17162                            }
17163                            chunk.text
17164                        })
17165                        .collect::<String>()
17166                        .into();
17167
17168                    drop(buffer);
17169
17170                    // Position the selection in the rename editor so that it matches the current selection.
17171                    this.show_local_selections = false;
17172                    let rename_editor = cx.new(|cx| {
17173                        let mut editor = Editor::single_line(window, cx);
17174                        editor.buffer.update(cx, |buffer, cx| {
17175                            buffer.edit([(0..0, old_name.clone())], None, cx)
17176                        });
17177                        let rename_selection_range = match cursor_offset_in_rename_range
17178                            .cmp(&cursor_offset_in_rename_range_end)
17179                        {
17180                            Ordering::Equal => {
17181                                editor.select_all(&SelectAll, window, cx);
17182                                return editor;
17183                            }
17184                            Ordering::Less => {
17185                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17186                            }
17187                            Ordering::Greater => {
17188                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17189                            }
17190                        };
17191                        if rename_selection_range.end > old_name.len() {
17192                            editor.select_all(&SelectAll, window, cx);
17193                        } else {
17194                            editor.change_selections(Default::default(), window, cx, |s| {
17195                                s.select_ranges([rename_selection_range]);
17196                            });
17197                        }
17198                        editor
17199                    });
17200                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17201                        if e == &EditorEvent::Focused {
17202                            cx.emit(EditorEvent::FocusedIn)
17203                        }
17204                    })
17205                    .detach();
17206
17207                    let write_highlights =
17208                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17209                    let read_highlights =
17210                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17211                    let ranges = write_highlights
17212                        .iter()
17213                        .flat_map(|(_, ranges)| ranges.iter())
17214                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17215                        .cloned()
17216                        .collect();
17217
17218                    this.highlight_text::<Rename>(
17219                        ranges,
17220                        HighlightStyle {
17221                            fade_out: Some(0.6),
17222                            ..Default::default()
17223                        },
17224                        cx,
17225                    );
17226                    let rename_focus_handle = rename_editor.focus_handle(cx);
17227                    window.focus(&rename_focus_handle);
17228                    let block_id = this.insert_blocks(
17229                        [BlockProperties {
17230                            style: BlockStyle::Flex,
17231                            placement: BlockPlacement::Below(range.start),
17232                            height: Some(1),
17233                            render: Arc::new({
17234                                let rename_editor = rename_editor.clone();
17235                                move |cx: &mut BlockContext| {
17236                                    let mut text_style = cx.editor_style.text.clone();
17237                                    if let Some(highlight_style) = old_highlight_id
17238                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17239                                    {
17240                                        text_style = text_style.highlight(highlight_style);
17241                                    }
17242                                    div()
17243                                        .block_mouse_except_scroll()
17244                                        .pl(cx.anchor_x)
17245                                        .child(EditorElement::new(
17246                                            &rename_editor,
17247                                            EditorStyle {
17248                                                background: cx.theme().system().transparent,
17249                                                local_player: cx.editor_style.local_player,
17250                                                text: text_style,
17251                                                scrollbar_width: cx.editor_style.scrollbar_width,
17252                                                syntax: cx.editor_style.syntax.clone(),
17253                                                status: cx.editor_style.status.clone(),
17254                                                inlay_hints_style: HighlightStyle {
17255                                                    font_weight: Some(FontWeight::BOLD),
17256                                                    ..make_inlay_hints_style(cx.app)
17257                                                },
17258                                                edit_prediction_styles: make_suggestion_styles(
17259                                                    cx.app,
17260                                                ),
17261                                                ..EditorStyle::default()
17262                                            },
17263                                        ))
17264                                        .into_any_element()
17265                                }
17266                            }),
17267                            priority: 0,
17268                        }],
17269                        Some(Autoscroll::fit()),
17270                        cx,
17271                    )[0];
17272                    this.pending_rename = Some(RenameState {
17273                        range,
17274                        old_name,
17275                        editor: rename_editor,
17276                        block_id,
17277                    });
17278                })?;
17279            }
17280
17281            Ok(())
17282        }))
17283    }
17284
17285    pub fn confirm_rename(
17286        &mut self,
17287        _: &ConfirmRename,
17288        window: &mut Window,
17289        cx: &mut Context<Self>,
17290    ) -> Option<Task<Result<()>>> {
17291        let rename = self.take_rename(false, window, cx)?;
17292        let workspace = self.workspace()?.downgrade();
17293        let (buffer, start) = self
17294            .buffer
17295            .read(cx)
17296            .text_anchor_for_position(rename.range.start, cx)?;
17297        let (end_buffer, _) = self
17298            .buffer
17299            .read(cx)
17300            .text_anchor_for_position(rename.range.end, cx)?;
17301        if buffer != end_buffer {
17302            return None;
17303        }
17304
17305        let old_name = rename.old_name;
17306        let new_name = rename.editor.read(cx).text(cx);
17307
17308        let rename = self.semantics_provider.as_ref()?.perform_rename(
17309            &buffer,
17310            start,
17311            new_name.clone(),
17312            cx,
17313        )?;
17314
17315        Some(cx.spawn_in(window, async move |editor, cx| {
17316            let project_transaction = rename.await?;
17317            Self::open_project_transaction(
17318                &editor,
17319                workspace,
17320                project_transaction,
17321                format!("Rename: {}{}", old_name, new_name),
17322                cx,
17323            )
17324            .await?;
17325
17326            editor.update(cx, |editor, cx| {
17327                editor.refresh_document_highlights(cx);
17328            })?;
17329            Ok(())
17330        }))
17331    }
17332
17333    fn take_rename(
17334        &mut self,
17335        moving_cursor: bool,
17336        window: &mut Window,
17337        cx: &mut Context<Self>,
17338    ) -> Option<RenameState> {
17339        let rename = self.pending_rename.take()?;
17340        if rename.editor.focus_handle(cx).is_focused(window) {
17341            window.focus(&self.focus_handle);
17342        }
17343
17344        self.remove_blocks(
17345            [rename.block_id].into_iter().collect(),
17346            Some(Autoscroll::fit()),
17347            cx,
17348        );
17349        self.clear_highlights::<Rename>(cx);
17350        self.show_local_selections = true;
17351
17352        if moving_cursor {
17353            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17354                editor
17355                    .selections
17356                    .newest::<usize>(&editor.display_snapshot(cx))
17357                    .head()
17358            });
17359
17360            // Update the selection to match the position of the selection inside
17361            // the rename editor.
17362            let snapshot = self.buffer.read(cx).read(cx);
17363            let rename_range = rename.range.to_offset(&snapshot);
17364            let cursor_in_editor = snapshot
17365                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17366                .min(rename_range.end);
17367            drop(snapshot);
17368
17369            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17370                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17371            });
17372        } else {
17373            self.refresh_document_highlights(cx);
17374        }
17375
17376        Some(rename)
17377    }
17378
17379    pub fn pending_rename(&self) -> Option<&RenameState> {
17380        self.pending_rename.as_ref()
17381    }
17382
17383    fn format(
17384        &mut self,
17385        _: &Format,
17386        window: &mut Window,
17387        cx: &mut Context<Self>,
17388    ) -> Option<Task<Result<()>>> {
17389        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17390
17391        let project = match &self.project {
17392            Some(project) => project.clone(),
17393            None => return None,
17394        };
17395
17396        Some(self.perform_format(
17397            project,
17398            FormatTrigger::Manual,
17399            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17400            window,
17401            cx,
17402        ))
17403    }
17404
17405    fn format_selections(
17406        &mut self,
17407        _: &FormatSelections,
17408        window: &mut Window,
17409        cx: &mut Context<Self>,
17410    ) -> Option<Task<Result<()>>> {
17411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17412
17413        let project = match &self.project {
17414            Some(project) => project.clone(),
17415            None => return None,
17416        };
17417
17418        let ranges = self
17419            .selections
17420            .all_adjusted(&self.display_snapshot(cx))
17421            .into_iter()
17422            .map(|selection| selection.range())
17423            .collect_vec();
17424
17425        Some(self.perform_format(
17426            project,
17427            FormatTrigger::Manual,
17428            FormatTarget::Ranges(ranges),
17429            window,
17430            cx,
17431        ))
17432    }
17433
17434    fn perform_format(
17435        &mut self,
17436        project: Entity<Project>,
17437        trigger: FormatTrigger,
17438        target: FormatTarget,
17439        window: &mut Window,
17440        cx: &mut Context<Self>,
17441    ) -> Task<Result<()>> {
17442        let buffer = self.buffer.clone();
17443        let (buffers, target) = match target {
17444            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17445            FormatTarget::Ranges(selection_ranges) => {
17446                let multi_buffer = buffer.read(cx);
17447                let snapshot = multi_buffer.read(cx);
17448                let mut buffers = HashSet::default();
17449                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17450                    BTreeMap::new();
17451                for selection_range in selection_ranges {
17452                    for (buffer, buffer_range, _) in
17453                        snapshot.range_to_buffer_ranges(selection_range)
17454                    {
17455                        let buffer_id = buffer.remote_id();
17456                        let start = buffer.anchor_before(buffer_range.start);
17457                        let end = buffer.anchor_after(buffer_range.end);
17458                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17459                        buffer_id_to_ranges
17460                            .entry(buffer_id)
17461                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17462                            .or_insert_with(|| vec![start..end]);
17463                    }
17464                }
17465                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17466            }
17467        };
17468
17469        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17470        let selections_prev = transaction_id_prev
17471            .and_then(|transaction_id_prev| {
17472                // default to selections as they were after the last edit, if we have them,
17473                // instead of how they are now.
17474                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17475                // will take you back to where you made the last edit, instead of staying where you scrolled
17476                self.selection_history
17477                    .transaction(transaction_id_prev)
17478                    .map(|t| t.0.clone())
17479            })
17480            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17481
17482        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17483        let format = project.update(cx, |project, cx| {
17484            project.format(buffers, target, true, trigger, cx)
17485        });
17486
17487        cx.spawn_in(window, async move |editor, cx| {
17488            let transaction = futures::select_biased! {
17489                transaction = format.log_err().fuse() => transaction,
17490                () = timeout => {
17491                    log::warn!("timed out waiting for formatting");
17492                    None
17493                }
17494            };
17495
17496            buffer
17497                .update(cx, |buffer, cx| {
17498                    if let Some(transaction) = transaction
17499                        && !buffer.is_singleton()
17500                    {
17501                        buffer.push_transaction(&transaction.0, cx);
17502                    }
17503                    cx.notify();
17504                })
17505                .ok();
17506
17507            if let Some(transaction_id_now) =
17508                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17509            {
17510                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17511                if has_new_transaction {
17512                    _ = editor.update(cx, |editor, _| {
17513                        editor
17514                            .selection_history
17515                            .insert_transaction(transaction_id_now, selections_prev);
17516                    });
17517                }
17518            }
17519
17520            Ok(())
17521        })
17522    }
17523
17524    fn organize_imports(
17525        &mut self,
17526        _: &OrganizeImports,
17527        window: &mut Window,
17528        cx: &mut Context<Self>,
17529    ) -> Option<Task<Result<()>>> {
17530        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17531        let project = match &self.project {
17532            Some(project) => project.clone(),
17533            None => return None,
17534        };
17535        Some(self.perform_code_action_kind(
17536            project,
17537            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17538            window,
17539            cx,
17540        ))
17541    }
17542
17543    fn perform_code_action_kind(
17544        &mut self,
17545        project: Entity<Project>,
17546        kind: CodeActionKind,
17547        window: &mut Window,
17548        cx: &mut Context<Self>,
17549    ) -> Task<Result<()>> {
17550        let buffer = self.buffer.clone();
17551        let buffers = buffer.read(cx).all_buffers();
17552        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17553        let apply_action = project.update(cx, |project, cx| {
17554            project.apply_code_action_kind(buffers, kind, true, cx)
17555        });
17556        cx.spawn_in(window, async move |_, cx| {
17557            let transaction = futures::select_biased! {
17558                () = timeout => {
17559                    log::warn!("timed out waiting for executing code action");
17560                    None
17561                }
17562                transaction = apply_action.log_err().fuse() => transaction,
17563            };
17564            buffer
17565                .update(cx, |buffer, cx| {
17566                    // check if we need this
17567                    if let Some(transaction) = transaction
17568                        && !buffer.is_singleton()
17569                    {
17570                        buffer.push_transaction(&transaction.0, cx);
17571                    }
17572                    cx.notify();
17573                })
17574                .ok();
17575            Ok(())
17576        })
17577    }
17578
17579    pub fn restart_language_server(
17580        &mut self,
17581        _: &RestartLanguageServer,
17582        _: &mut Window,
17583        cx: &mut Context<Self>,
17584    ) {
17585        if let Some(project) = self.project.clone() {
17586            self.buffer.update(cx, |multi_buffer, cx| {
17587                project.update(cx, |project, cx| {
17588                    project.restart_language_servers_for_buffers(
17589                        multi_buffer.all_buffers().into_iter().collect(),
17590                        HashSet::default(),
17591                        cx,
17592                    );
17593                });
17594            })
17595        }
17596    }
17597
17598    pub fn stop_language_server(
17599        &mut self,
17600        _: &StopLanguageServer,
17601        _: &mut Window,
17602        cx: &mut Context<Self>,
17603    ) {
17604        if let Some(project) = self.project.clone() {
17605            self.buffer.update(cx, |multi_buffer, cx| {
17606                project.update(cx, |project, cx| {
17607                    project.stop_language_servers_for_buffers(
17608                        multi_buffer.all_buffers().into_iter().collect(),
17609                        HashSet::default(),
17610                        cx,
17611                    );
17612                    cx.emit(project::Event::RefreshInlayHints);
17613                });
17614            });
17615        }
17616    }
17617
17618    fn cancel_language_server_work(
17619        workspace: &mut Workspace,
17620        _: &actions::CancelLanguageServerWork,
17621        _: &mut Window,
17622        cx: &mut Context<Workspace>,
17623    ) {
17624        let project = workspace.project();
17625        let buffers = workspace
17626            .active_item(cx)
17627            .and_then(|item| item.act_as::<Editor>(cx))
17628            .map_or(HashSet::default(), |editor| {
17629                editor.read(cx).buffer.read(cx).all_buffers()
17630            });
17631        project.update(cx, |project, cx| {
17632            project.cancel_language_server_work_for_buffers(buffers, cx);
17633        });
17634    }
17635
17636    fn show_character_palette(
17637        &mut self,
17638        _: &ShowCharacterPalette,
17639        window: &mut Window,
17640        _: &mut Context<Self>,
17641    ) {
17642        window.show_character_palette();
17643    }
17644
17645    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17646        if !self.diagnostics_enabled() {
17647            return;
17648        }
17649
17650        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17651            let buffer = self.buffer.read(cx).snapshot(cx);
17652            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17653            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17654            let is_valid = buffer
17655                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17656                .any(|entry| {
17657                    entry.diagnostic.is_primary
17658                        && !entry.range.is_empty()
17659                        && entry.range.start == primary_range_start
17660                        && entry.diagnostic.message == active_diagnostics.active_message
17661                });
17662
17663            if !is_valid {
17664                self.dismiss_diagnostics(cx);
17665            }
17666        }
17667    }
17668
17669    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17670        match &self.active_diagnostics {
17671            ActiveDiagnostic::Group(group) => Some(group),
17672            _ => None,
17673        }
17674    }
17675
17676    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17677        if !self.diagnostics_enabled() {
17678            return;
17679        }
17680        self.dismiss_diagnostics(cx);
17681        self.active_diagnostics = ActiveDiagnostic::All;
17682    }
17683
17684    fn activate_diagnostics(
17685        &mut self,
17686        buffer_id: BufferId,
17687        diagnostic: DiagnosticEntryRef<'_, usize>,
17688        window: &mut Window,
17689        cx: &mut Context<Self>,
17690    ) {
17691        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17692            return;
17693        }
17694        self.dismiss_diagnostics(cx);
17695        let snapshot = self.snapshot(window, cx);
17696        let buffer = self.buffer.read(cx).snapshot(cx);
17697        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17698            return;
17699        };
17700
17701        let diagnostic_group = buffer
17702            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17703            .collect::<Vec<_>>();
17704
17705        let blocks =
17706            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17707
17708        let blocks = self.display_map.update(cx, |display_map, cx| {
17709            display_map.insert_blocks(blocks, cx).into_iter().collect()
17710        });
17711        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17712            active_range: buffer.anchor_before(diagnostic.range.start)
17713                ..buffer.anchor_after(diagnostic.range.end),
17714            active_message: diagnostic.diagnostic.message.clone(),
17715            group_id: diagnostic.diagnostic.group_id,
17716            blocks,
17717        });
17718        cx.notify();
17719    }
17720
17721    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17722        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17723            return;
17724        };
17725
17726        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17727        if let ActiveDiagnostic::Group(group) = prev {
17728            self.display_map.update(cx, |display_map, cx| {
17729                display_map.remove_blocks(group.blocks, cx);
17730            });
17731            cx.notify();
17732        }
17733    }
17734
17735    /// Disable inline diagnostics rendering for this editor.
17736    pub fn disable_inline_diagnostics(&mut self) {
17737        self.inline_diagnostics_enabled = false;
17738        self.inline_diagnostics_update = Task::ready(());
17739        self.inline_diagnostics.clear();
17740    }
17741
17742    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17743        self.diagnostics_enabled = false;
17744        self.dismiss_diagnostics(cx);
17745        self.inline_diagnostics_update = Task::ready(());
17746        self.inline_diagnostics.clear();
17747    }
17748
17749    pub fn disable_word_completions(&mut self) {
17750        self.word_completions_enabled = false;
17751    }
17752
17753    pub fn diagnostics_enabled(&self) -> bool {
17754        self.diagnostics_enabled && self.mode.is_full()
17755    }
17756
17757    pub fn inline_diagnostics_enabled(&self) -> bool {
17758        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17759    }
17760
17761    pub fn show_inline_diagnostics(&self) -> bool {
17762        self.show_inline_diagnostics
17763    }
17764
17765    pub fn toggle_inline_diagnostics(
17766        &mut self,
17767        _: &ToggleInlineDiagnostics,
17768        window: &mut Window,
17769        cx: &mut Context<Editor>,
17770    ) {
17771        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17772        self.refresh_inline_diagnostics(false, window, cx);
17773    }
17774
17775    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17776        self.diagnostics_max_severity = severity;
17777        self.display_map.update(cx, |display_map, _| {
17778            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17779        });
17780    }
17781
17782    pub fn toggle_diagnostics(
17783        &mut self,
17784        _: &ToggleDiagnostics,
17785        window: &mut Window,
17786        cx: &mut Context<Editor>,
17787    ) {
17788        if !self.diagnostics_enabled() {
17789            return;
17790        }
17791
17792        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17793            EditorSettings::get_global(cx)
17794                .diagnostics_max_severity
17795                .filter(|severity| severity != &DiagnosticSeverity::Off)
17796                .unwrap_or(DiagnosticSeverity::Hint)
17797        } else {
17798            DiagnosticSeverity::Off
17799        };
17800        self.set_max_diagnostics_severity(new_severity, cx);
17801        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17802            self.active_diagnostics = ActiveDiagnostic::None;
17803            self.inline_diagnostics_update = Task::ready(());
17804            self.inline_diagnostics.clear();
17805        } else {
17806            self.refresh_inline_diagnostics(false, window, cx);
17807        }
17808
17809        cx.notify();
17810    }
17811
17812    pub fn toggle_minimap(
17813        &mut self,
17814        _: &ToggleMinimap,
17815        window: &mut Window,
17816        cx: &mut Context<Editor>,
17817    ) {
17818        if self.supports_minimap(cx) {
17819            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17820        }
17821    }
17822
17823    fn refresh_inline_diagnostics(
17824        &mut self,
17825        debounce: bool,
17826        window: &mut Window,
17827        cx: &mut Context<Self>,
17828    ) {
17829        let max_severity = ProjectSettings::get_global(cx)
17830            .diagnostics
17831            .inline
17832            .max_severity
17833            .unwrap_or(self.diagnostics_max_severity);
17834
17835        if !self.inline_diagnostics_enabled()
17836            || !self.show_inline_diagnostics
17837            || max_severity == DiagnosticSeverity::Off
17838        {
17839            self.inline_diagnostics_update = Task::ready(());
17840            self.inline_diagnostics.clear();
17841            return;
17842        }
17843
17844        let debounce_ms = ProjectSettings::get_global(cx)
17845            .diagnostics
17846            .inline
17847            .update_debounce_ms;
17848        let debounce = if debounce && debounce_ms > 0 {
17849            Some(Duration::from_millis(debounce_ms))
17850        } else {
17851            None
17852        };
17853        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17854            if let Some(debounce) = debounce {
17855                cx.background_executor().timer(debounce).await;
17856            }
17857            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17858                editor
17859                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17860                    .ok()
17861            }) else {
17862                return;
17863            };
17864
17865            let new_inline_diagnostics = cx
17866                .background_spawn(async move {
17867                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17868                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17869                        let message = diagnostic_entry
17870                            .diagnostic
17871                            .message
17872                            .split_once('\n')
17873                            .map(|(line, _)| line)
17874                            .map(SharedString::new)
17875                            .unwrap_or_else(|| {
17876                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17877                            });
17878                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17879                        let (Ok(i) | Err(i)) = inline_diagnostics
17880                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17881                        inline_diagnostics.insert(
17882                            i,
17883                            (
17884                                start_anchor,
17885                                InlineDiagnostic {
17886                                    message,
17887                                    group_id: diagnostic_entry.diagnostic.group_id,
17888                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17889                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17890                                    severity: diagnostic_entry.diagnostic.severity,
17891                                },
17892                            ),
17893                        );
17894                    }
17895                    inline_diagnostics
17896                })
17897                .await;
17898
17899            editor
17900                .update(cx, |editor, cx| {
17901                    editor.inline_diagnostics = new_inline_diagnostics;
17902                    cx.notify();
17903                })
17904                .ok();
17905        });
17906    }
17907
17908    fn pull_diagnostics(
17909        &mut self,
17910        buffer_id: Option<BufferId>,
17911        window: &Window,
17912        cx: &mut Context<Self>,
17913    ) -> Option<()> {
17914        if self.ignore_lsp_data() {
17915            return None;
17916        }
17917        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17918            .diagnostics
17919            .lsp_pull_diagnostics;
17920        if !pull_diagnostics_settings.enabled {
17921            return None;
17922        }
17923        let project = self.project()?.downgrade();
17924        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17925        let mut buffers = self.buffer.read(cx).all_buffers();
17926        buffers.retain(|buffer| {
17927            let buffer_id_to_retain = buffer.read(cx).remote_id();
17928            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17929                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17930        });
17931        if buffers.is_empty() {
17932            self.pull_diagnostics_task = Task::ready(());
17933            return None;
17934        }
17935
17936        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17937            cx.background_executor().timer(debounce).await;
17938
17939            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17940                buffers
17941                    .into_iter()
17942                    .filter_map(|buffer| {
17943                        project
17944                            .update(cx, |project, cx| {
17945                                project.lsp_store().update(cx, |lsp_store, cx| {
17946                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17947                                })
17948                            })
17949                            .ok()
17950                    })
17951                    .collect::<FuturesUnordered<_>>()
17952            }) else {
17953                return;
17954            };
17955
17956            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17957                match pull_task {
17958                    Ok(()) => {
17959                        if editor
17960                            .update_in(cx, |editor, window, cx| {
17961                                editor.update_diagnostics_state(window, cx);
17962                            })
17963                            .is_err()
17964                        {
17965                            return;
17966                        }
17967                    }
17968                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17969                }
17970            }
17971        });
17972
17973        Some(())
17974    }
17975
17976    pub fn set_selections_from_remote(
17977        &mut self,
17978        selections: Vec<Selection<Anchor>>,
17979        pending_selection: Option<Selection<Anchor>>,
17980        window: &mut Window,
17981        cx: &mut Context<Self>,
17982    ) {
17983        let old_cursor_position = self.selections.newest_anchor().head();
17984        self.selections.change_with(cx, |s| {
17985            s.select_anchors(selections);
17986            if let Some(pending_selection) = pending_selection {
17987                s.set_pending(pending_selection, SelectMode::Character);
17988            } else {
17989                s.clear_pending();
17990            }
17991        });
17992        self.selections_did_change(
17993            false,
17994            &old_cursor_position,
17995            SelectionEffects::default(),
17996            window,
17997            cx,
17998        );
17999    }
18000
18001    pub fn transact(
18002        &mut self,
18003        window: &mut Window,
18004        cx: &mut Context<Self>,
18005        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18006    ) -> Option<TransactionId> {
18007        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18008            this.start_transaction_at(Instant::now(), window, cx);
18009            update(this, window, cx);
18010            this.end_transaction_at(Instant::now(), cx)
18011        })
18012    }
18013
18014    pub fn start_transaction_at(
18015        &mut self,
18016        now: Instant,
18017        window: &mut Window,
18018        cx: &mut Context<Self>,
18019    ) -> Option<TransactionId> {
18020        self.end_selection(window, cx);
18021        if let Some(tx_id) = self
18022            .buffer
18023            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18024        {
18025            self.selection_history
18026                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18027            cx.emit(EditorEvent::TransactionBegun {
18028                transaction_id: tx_id,
18029            });
18030            Some(tx_id)
18031        } else {
18032            None
18033        }
18034    }
18035
18036    pub fn end_transaction_at(
18037        &mut self,
18038        now: Instant,
18039        cx: &mut Context<Self>,
18040    ) -> Option<TransactionId> {
18041        if let Some(transaction_id) = self
18042            .buffer
18043            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18044        {
18045            if let Some((_, end_selections)) =
18046                self.selection_history.transaction_mut(transaction_id)
18047            {
18048                *end_selections = Some(self.selections.disjoint_anchors_arc());
18049            } else {
18050                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18051            }
18052
18053            cx.emit(EditorEvent::Edited { transaction_id });
18054            Some(transaction_id)
18055        } else {
18056            None
18057        }
18058    }
18059
18060    pub fn modify_transaction_selection_history(
18061        &mut self,
18062        transaction_id: TransactionId,
18063        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18064    ) -> bool {
18065        self.selection_history
18066            .transaction_mut(transaction_id)
18067            .map(modify)
18068            .is_some()
18069    }
18070
18071    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18072        if self.selection_mark_mode {
18073            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18074                s.move_with(|_, sel| {
18075                    sel.collapse_to(sel.head(), SelectionGoal::None);
18076                });
18077            })
18078        }
18079        self.selection_mark_mode = true;
18080        cx.notify();
18081    }
18082
18083    pub fn swap_selection_ends(
18084        &mut self,
18085        _: &actions::SwapSelectionEnds,
18086        window: &mut Window,
18087        cx: &mut Context<Self>,
18088    ) {
18089        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18090            s.move_with(|_, sel| {
18091                if sel.start != sel.end {
18092                    sel.reversed = !sel.reversed
18093                }
18094            });
18095        });
18096        self.request_autoscroll(Autoscroll::newest(), cx);
18097        cx.notify();
18098    }
18099
18100    pub fn toggle_focus(
18101        workspace: &mut Workspace,
18102        _: &actions::ToggleFocus,
18103        window: &mut Window,
18104        cx: &mut Context<Workspace>,
18105    ) {
18106        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18107            return;
18108        };
18109        workspace.activate_item(&item, true, true, window, cx);
18110    }
18111
18112    pub fn toggle_fold(
18113        &mut self,
18114        _: &actions::ToggleFold,
18115        window: &mut Window,
18116        cx: &mut Context<Self>,
18117    ) {
18118        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18119            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18120            let selection = self.selections.newest::<Point>(&display_map);
18121
18122            let range = if selection.is_empty() {
18123                let point = selection.head().to_display_point(&display_map);
18124                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18125                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18126                    .to_point(&display_map);
18127                start..end
18128            } else {
18129                selection.range()
18130            };
18131            if display_map.folds_in_range(range).next().is_some() {
18132                self.unfold_lines(&Default::default(), window, cx)
18133            } else {
18134                self.fold(&Default::default(), window, cx)
18135            }
18136        } else {
18137            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18138            let buffer_ids: HashSet<_> = self
18139                .selections
18140                .disjoint_anchor_ranges()
18141                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18142                .collect();
18143
18144            let should_unfold = buffer_ids
18145                .iter()
18146                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18147
18148            for buffer_id in buffer_ids {
18149                if should_unfold {
18150                    self.unfold_buffer(buffer_id, cx);
18151                } else {
18152                    self.fold_buffer(buffer_id, cx);
18153                }
18154            }
18155        }
18156    }
18157
18158    pub fn toggle_fold_recursive(
18159        &mut self,
18160        _: &actions::ToggleFoldRecursive,
18161        window: &mut Window,
18162        cx: &mut Context<Self>,
18163    ) {
18164        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18165
18166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18167        let range = if selection.is_empty() {
18168            let point = selection.head().to_display_point(&display_map);
18169            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18170            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18171                .to_point(&display_map);
18172            start..end
18173        } else {
18174            selection.range()
18175        };
18176        if display_map.folds_in_range(range).next().is_some() {
18177            self.unfold_recursive(&Default::default(), window, cx)
18178        } else {
18179            self.fold_recursive(&Default::default(), window, cx)
18180        }
18181    }
18182
18183    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18184        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18185            let mut to_fold = Vec::new();
18186            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18187            let selections = self.selections.all_adjusted(&display_map);
18188
18189            for selection in selections {
18190                let range = selection.range().sorted();
18191                let buffer_start_row = range.start.row;
18192
18193                if range.start.row != range.end.row {
18194                    let mut found = false;
18195                    let mut row = range.start.row;
18196                    while row <= range.end.row {
18197                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18198                        {
18199                            found = true;
18200                            row = crease.range().end.row + 1;
18201                            to_fold.push(crease);
18202                        } else {
18203                            row += 1
18204                        }
18205                    }
18206                    if found {
18207                        continue;
18208                    }
18209                }
18210
18211                for row in (0..=range.start.row).rev() {
18212                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18213                        && crease.range().end.row >= buffer_start_row
18214                    {
18215                        to_fold.push(crease);
18216                        if row <= range.start.row {
18217                            break;
18218                        }
18219                    }
18220                }
18221            }
18222
18223            self.fold_creases(to_fold, true, window, cx);
18224        } else {
18225            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18226            let buffer_ids = self
18227                .selections
18228                .disjoint_anchor_ranges()
18229                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18230                .collect::<HashSet<_>>();
18231            for buffer_id in buffer_ids {
18232                self.fold_buffer(buffer_id, cx);
18233            }
18234        }
18235    }
18236
18237    pub fn toggle_fold_all(
18238        &mut self,
18239        _: &actions::ToggleFoldAll,
18240        window: &mut Window,
18241        cx: &mut Context<Self>,
18242    ) {
18243        if self.buffer.read(cx).is_singleton() {
18244            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18245            let has_folds = display_map
18246                .folds_in_range(0..display_map.buffer_snapshot().len())
18247                .next()
18248                .is_some();
18249
18250            if has_folds {
18251                self.unfold_all(&actions::UnfoldAll, window, cx);
18252            } else {
18253                self.fold_all(&actions::FoldAll, window, cx);
18254            }
18255        } else {
18256            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18257            let should_unfold = buffer_ids
18258                .iter()
18259                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18260
18261            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18262                editor
18263                    .update_in(cx, |editor, _, cx| {
18264                        for buffer_id in buffer_ids {
18265                            if should_unfold {
18266                                editor.unfold_buffer(buffer_id, cx);
18267                            } else {
18268                                editor.fold_buffer(buffer_id, cx);
18269                            }
18270                        }
18271                    })
18272                    .ok();
18273            });
18274        }
18275    }
18276
18277    fn fold_at_level(
18278        &mut self,
18279        fold_at: &FoldAtLevel,
18280        window: &mut Window,
18281        cx: &mut Context<Self>,
18282    ) {
18283        if !self.buffer.read(cx).is_singleton() {
18284            return;
18285        }
18286
18287        let fold_at_level = fold_at.0;
18288        let snapshot = self.buffer.read(cx).snapshot(cx);
18289        let mut to_fold = Vec::new();
18290        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18291
18292        let row_ranges_to_keep: Vec<Range<u32>> = self
18293            .selections
18294            .all::<Point>(&self.display_snapshot(cx))
18295            .into_iter()
18296            .map(|sel| sel.start.row..sel.end.row)
18297            .collect();
18298
18299        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18300            while start_row < end_row {
18301                match self
18302                    .snapshot(window, cx)
18303                    .crease_for_buffer_row(MultiBufferRow(start_row))
18304                {
18305                    Some(crease) => {
18306                        let nested_start_row = crease.range().start.row + 1;
18307                        let nested_end_row = crease.range().end.row;
18308
18309                        if current_level < fold_at_level {
18310                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18311                        } else if current_level == fold_at_level {
18312                            // Fold iff there is no selection completely contained within the fold region
18313                            if !row_ranges_to_keep.iter().any(|selection| {
18314                                selection.end >= nested_start_row
18315                                    && selection.start <= nested_end_row
18316                            }) {
18317                                to_fold.push(crease);
18318                            }
18319                        }
18320
18321                        start_row = nested_end_row + 1;
18322                    }
18323                    None => start_row += 1,
18324                }
18325            }
18326        }
18327
18328        self.fold_creases(to_fold, true, window, cx);
18329    }
18330
18331    pub fn fold_at_level_1(
18332        &mut self,
18333        _: &actions::FoldAtLevel1,
18334        window: &mut Window,
18335        cx: &mut Context<Self>,
18336    ) {
18337        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18338    }
18339
18340    pub fn fold_at_level_2(
18341        &mut self,
18342        _: &actions::FoldAtLevel2,
18343        window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18347    }
18348
18349    pub fn fold_at_level_3(
18350        &mut self,
18351        _: &actions::FoldAtLevel3,
18352        window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) {
18355        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18356    }
18357
18358    pub fn fold_at_level_4(
18359        &mut self,
18360        _: &actions::FoldAtLevel4,
18361        window: &mut Window,
18362        cx: &mut Context<Self>,
18363    ) {
18364        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18365    }
18366
18367    pub fn fold_at_level_5(
18368        &mut self,
18369        _: &actions::FoldAtLevel5,
18370        window: &mut Window,
18371        cx: &mut Context<Self>,
18372    ) {
18373        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18374    }
18375
18376    pub fn fold_at_level_6(
18377        &mut self,
18378        _: &actions::FoldAtLevel6,
18379        window: &mut Window,
18380        cx: &mut Context<Self>,
18381    ) {
18382        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18383    }
18384
18385    pub fn fold_at_level_7(
18386        &mut self,
18387        _: &actions::FoldAtLevel7,
18388        window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) {
18391        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18392    }
18393
18394    pub fn fold_at_level_8(
18395        &mut self,
18396        _: &actions::FoldAtLevel8,
18397        window: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) {
18400        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18401    }
18402
18403    pub fn fold_at_level_9(
18404        &mut self,
18405        _: &actions::FoldAtLevel9,
18406        window: &mut Window,
18407        cx: &mut Context<Self>,
18408    ) {
18409        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18410    }
18411
18412    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18413        if self.buffer.read(cx).is_singleton() {
18414            let mut fold_ranges = Vec::new();
18415            let snapshot = self.buffer.read(cx).snapshot(cx);
18416
18417            for row in 0..snapshot.max_row().0 {
18418                if let Some(foldable_range) = self
18419                    .snapshot(window, cx)
18420                    .crease_for_buffer_row(MultiBufferRow(row))
18421                {
18422                    fold_ranges.push(foldable_range);
18423                }
18424            }
18425
18426            self.fold_creases(fold_ranges, true, window, cx);
18427        } else {
18428            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18429                editor
18430                    .update_in(cx, |editor, _, cx| {
18431                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18432                            editor.fold_buffer(buffer_id, cx);
18433                        }
18434                    })
18435                    .ok();
18436            });
18437        }
18438    }
18439
18440    pub fn fold_function_bodies(
18441        &mut self,
18442        _: &actions::FoldFunctionBodies,
18443        window: &mut Window,
18444        cx: &mut Context<Self>,
18445    ) {
18446        let snapshot = self.buffer.read(cx).snapshot(cx);
18447
18448        let ranges = snapshot
18449            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18450            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18451            .collect::<Vec<_>>();
18452
18453        let creases = ranges
18454            .into_iter()
18455            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18456            .collect();
18457
18458        self.fold_creases(creases, true, window, cx);
18459    }
18460
18461    pub fn fold_recursive(
18462        &mut self,
18463        _: &actions::FoldRecursive,
18464        window: &mut Window,
18465        cx: &mut Context<Self>,
18466    ) {
18467        let mut to_fold = Vec::new();
18468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18469        let selections = self.selections.all_adjusted(&display_map);
18470
18471        for selection in selections {
18472            let range = selection.range().sorted();
18473            let buffer_start_row = range.start.row;
18474
18475            if range.start.row != range.end.row {
18476                let mut found = false;
18477                for row in range.start.row..=range.end.row {
18478                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18479                        found = true;
18480                        to_fold.push(crease);
18481                    }
18482                }
18483                if found {
18484                    continue;
18485                }
18486            }
18487
18488            for row in (0..=range.start.row).rev() {
18489                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18490                    if crease.range().end.row >= buffer_start_row {
18491                        to_fold.push(crease);
18492                    } else {
18493                        break;
18494                    }
18495                }
18496            }
18497        }
18498
18499        self.fold_creases(to_fold, true, window, cx);
18500    }
18501
18502    pub fn fold_at(
18503        &mut self,
18504        buffer_row: MultiBufferRow,
18505        window: &mut Window,
18506        cx: &mut Context<Self>,
18507    ) {
18508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18509
18510        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18511            let autoscroll = self
18512                .selections
18513                .all::<Point>(&display_map)
18514                .iter()
18515                .any(|selection| crease.range().overlaps(&selection.range()));
18516
18517            self.fold_creases(vec![crease], autoscroll, window, cx);
18518        }
18519    }
18520
18521    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18522        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18523            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18524            let buffer = display_map.buffer_snapshot();
18525            let selections = self.selections.all::<Point>(&display_map);
18526            let ranges = selections
18527                .iter()
18528                .map(|s| {
18529                    let range = s.display_range(&display_map).sorted();
18530                    let mut start = range.start.to_point(&display_map);
18531                    let mut end = range.end.to_point(&display_map);
18532                    start.column = 0;
18533                    end.column = buffer.line_len(MultiBufferRow(end.row));
18534                    start..end
18535                })
18536                .collect::<Vec<_>>();
18537
18538            self.unfold_ranges(&ranges, true, true, cx);
18539        } else {
18540            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18541            let buffer_ids = self
18542                .selections
18543                .disjoint_anchor_ranges()
18544                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18545                .collect::<HashSet<_>>();
18546            for buffer_id in buffer_ids {
18547                self.unfold_buffer(buffer_id, cx);
18548            }
18549        }
18550    }
18551
18552    pub fn unfold_recursive(
18553        &mut self,
18554        _: &UnfoldRecursive,
18555        _window: &mut Window,
18556        cx: &mut Context<Self>,
18557    ) {
18558        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18559        let selections = self.selections.all::<Point>(&display_map);
18560        let ranges = selections
18561            .iter()
18562            .map(|s| {
18563                let mut range = s.display_range(&display_map).sorted();
18564                *range.start.column_mut() = 0;
18565                *range.end.column_mut() = display_map.line_len(range.end.row());
18566                let start = range.start.to_point(&display_map);
18567                let end = range.end.to_point(&display_map);
18568                start..end
18569            })
18570            .collect::<Vec<_>>();
18571
18572        self.unfold_ranges(&ranges, true, true, cx);
18573    }
18574
18575    pub fn unfold_at(
18576        &mut self,
18577        buffer_row: MultiBufferRow,
18578        _window: &mut Window,
18579        cx: &mut Context<Self>,
18580    ) {
18581        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18582
18583        let intersection_range = Point::new(buffer_row.0, 0)
18584            ..Point::new(
18585                buffer_row.0,
18586                display_map.buffer_snapshot().line_len(buffer_row),
18587            );
18588
18589        let autoscroll = self
18590            .selections
18591            .all::<Point>(&display_map)
18592            .iter()
18593            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18594
18595        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18596    }
18597
18598    pub fn unfold_all(
18599        &mut self,
18600        _: &actions::UnfoldAll,
18601        _window: &mut Window,
18602        cx: &mut Context<Self>,
18603    ) {
18604        if self.buffer.read(cx).is_singleton() {
18605            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18606            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18607        } else {
18608            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18609                editor
18610                    .update(cx, |editor, cx| {
18611                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18612                            editor.unfold_buffer(buffer_id, cx);
18613                        }
18614                    })
18615                    .ok();
18616            });
18617        }
18618    }
18619
18620    pub fn fold_selected_ranges(
18621        &mut self,
18622        _: &FoldSelectedRanges,
18623        window: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18627        let selections = self.selections.all_adjusted(&display_map);
18628        let ranges = selections
18629            .into_iter()
18630            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18631            .collect::<Vec<_>>();
18632        self.fold_creases(ranges, true, window, cx);
18633    }
18634
18635    pub fn fold_ranges<T: ToOffset + Clone>(
18636        &mut self,
18637        ranges: Vec<Range<T>>,
18638        auto_scroll: bool,
18639        window: &mut Window,
18640        cx: &mut Context<Self>,
18641    ) {
18642        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18643        let ranges = ranges
18644            .into_iter()
18645            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18646            .collect::<Vec<_>>();
18647        self.fold_creases(ranges, auto_scroll, window, cx);
18648    }
18649
18650    pub fn fold_creases<T: ToOffset + Clone>(
18651        &mut self,
18652        creases: Vec<Crease<T>>,
18653        auto_scroll: bool,
18654        _window: &mut Window,
18655        cx: &mut Context<Self>,
18656    ) {
18657        if creases.is_empty() {
18658            return;
18659        }
18660
18661        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18662
18663        if auto_scroll {
18664            self.request_autoscroll(Autoscroll::fit(), cx);
18665        }
18666
18667        cx.notify();
18668
18669        self.scrollbar_marker_state.dirty = true;
18670        self.folds_did_change(cx);
18671    }
18672
18673    /// Removes any folds whose ranges intersect any of the given ranges.
18674    pub fn unfold_ranges<T: ToOffset + Clone>(
18675        &mut self,
18676        ranges: &[Range<T>],
18677        inclusive: bool,
18678        auto_scroll: bool,
18679        cx: &mut Context<Self>,
18680    ) {
18681        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18682            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18683        });
18684        self.folds_did_change(cx);
18685    }
18686
18687    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18688        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18689            return;
18690        }
18691        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18692        self.display_map.update(cx, |display_map, cx| {
18693            display_map.fold_buffers([buffer_id], cx)
18694        });
18695        cx.emit(EditorEvent::BufferFoldToggled {
18696            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18697            folded: true,
18698        });
18699        cx.notify();
18700    }
18701
18702    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18703        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18704            return;
18705        }
18706        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18707        self.display_map.update(cx, |display_map, cx| {
18708            display_map.unfold_buffers([buffer_id], cx);
18709        });
18710        cx.emit(EditorEvent::BufferFoldToggled {
18711            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18712            folded: false,
18713        });
18714        cx.notify();
18715    }
18716
18717    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18718        self.display_map.read(cx).is_buffer_folded(buffer)
18719    }
18720
18721    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18722        self.display_map.read(cx).folded_buffers()
18723    }
18724
18725    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18726        self.display_map.update(cx, |display_map, cx| {
18727            display_map.disable_header_for_buffer(buffer_id, cx);
18728        });
18729        cx.notify();
18730    }
18731
18732    /// Removes any folds with the given ranges.
18733    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18734        &mut self,
18735        ranges: &[Range<T>],
18736        type_id: TypeId,
18737        auto_scroll: bool,
18738        cx: &mut Context<Self>,
18739    ) {
18740        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18741            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18742        });
18743        self.folds_did_change(cx);
18744    }
18745
18746    fn remove_folds_with<T: ToOffset + Clone>(
18747        &mut self,
18748        ranges: &[Range<T>],
18749        auto_scroll: bool,
18750        cx: &mut Context<Self>,
18751        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18752    ) {
18753        if ranges.is_empty() {
18754            return;
18755        }
18756
18757        let mut buffers_affected = HashSet::default();
18758        let multi_buffer = self.buffer().read(cx);
18759        for range in ranges {
18760            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18761                buffers_affected.insert(buffer.read(cx).remote_id());
18762            };
18763        }
18764
18765        self.display_map.update(cx, update);
18766
18767        if auto_scroll {
18768            self.request_autoscroll(Autoscroll::fit(), cx);
18769        }
18770
18771        cx.notify();
18772        self.scrollbar_marker_state.dirty = true;
18773        self.active_indent_guides_state.dirty = true;
18774    }
18775
18776    pub fn update_renderer_widths(
18777        &mut self,
18778        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18779        cx: &mut Context<Self>,
18780    ) -> bool {
18781        self.display_map
18782            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18783    }
18784
18785    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18786        self.display_map.read(cx).fold_placeholder.clone()
18787    }
18788
18789    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18790        self.buffer.update(cx, |buffer, cx| {
18791            buffer.set_all_diff_hunks_expanded(cx);
18792        });
18793    }
18794
18795    pub fn expand_all_diff_hunks(
18796        &mut self,
18797        _: &ExpandAllDiffHunks,
18798        _window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        self.buffer.update(cx, |buffer, cx| {
18802            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18803        });
18804    }
18805
18806    pub fn collapse_all_diff_hunks(
18807        &mut self,
18808        _: &CollapseAllDiffHunks,
18809        _window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        self.buffer.update(cx, |buffer, cx| {
18813            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18814        });
18815    }
18816
18817    pub fn toggle_selected_diff_hunks(
18818        &mut self,
18819        _: &ToggleSelectedDiffHunks,
18820        _window: &mut Window,
18821        cx: &mut Context<Self>,
18822    ) {
18823        let ranges: Vec<_> = self
18824            .selections
18825            .disjoint_anchors()
18826            .iter()
18827            .map(|s| s.range())
18828            .collect();
18829        self.toggle_diff_hunks_in_ranges(ranges, cx);
18830    }
18831
18832    pub fn diff_hunks_in_ranges<'a>(
18833        &'a self,
18834        ranges: &'a [Range<Anchor>],
18835        buffer: &'a MultiBufferSnapshot,
18836    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18837        ranges.iter().flat_map(move |range| {
18838            let end_excerpt_id = range.end.excerpt_id;
18839            let range = range.to_point(buffer);
18840            let mut peek_end = range.end;
18841            if range.end.row < buffer.max_row().0 {
18842                peek_end = Point::new(range.end.row + 1, 0);
18843            }
18844            buffer
18845                .diff_hunks_in_range(range.start..peek_end)
18846                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18847        })
18848    }
18849
18850    pub fn has_stageable_diff_hunks_in_ranges(
18851        &self,
18852        ranges: &[Range<Anchor>],
18853        snapshot: &MultiBufferSnapshot,
18854    ) -> bool {
18855        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18856        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18857    }
18858
18859    pub fn toggle_staged_selected_diff_hunks(
18860        &mut self,
18861        _: &::git::ToggleStaged,
18862        _: &mut Window,
18863        cx: &mut Context<Self>,
18864    ) {
18865        let snapshot = self.buffer.read(cx).snapshot(cx);
18866        let ranges: Vec<_> = self
18867            .selections
18868            .disjoint_anchors()
18869            .iter()
18870            .map(|s| s.range())
18871            .collect();
18872        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18873        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18874    }
18875
18876    pub fn set_render_diff_hunk_controls(
18877        &mut self,
18878        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18879        cx: &mut Context<Self>,
18880    ) {
18881        self.render_diff_hunk_controls = render_diff_hunk_controls;
18882        cx.notify();
18883    }
18884
18885    pub fn stage_and_next(
18886        &mut self,
18887        _: &::git::StageAndNext,
18888        window: &mut Window,
18889        cx: &mut Context<Self>,
18890    ) {
18891        self.do_stage_or_unstage_and_next(true, window, cx);
18892    }
18893
18894    pub fn unstage_and_next(
18895        &mut self,
18896        _: &::git::UnstageAndNext,
18897        window: &mut Window,
18898        cx: &mut Context<Self>,
18899    ) {
18900        self.do_stage_or_unstage_and_next(false, window, cx);
18901    }
18902
18903    pub fn stage_or_unstage_diff_hunks(
18904        &mut self,
18905        stage: bool,
18906        ranges: Vec<Range<Anchor>>,
18907        cx: &mut Context<Self>,
18908    ) {
18909        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18910        cx.spawn(async move |this, cx| {
18911            task.await?;
18912            this.update(cx, |this, cx| {
18913                let snapshot = this.buffer.read(cx).snapshot(cx);
18914                let chunk_by = this
18915                    .diff_hunks_in_ranges(&ranges, &snapshot)
18916                    .chunk_by(|hunk| hunk.buffer_id);
18917                for (buffer_id, hunks) in &chunk_by {
18918                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18919                }
18920            })
18921        })
18922        .detach_and_log_err(cx);
18923    }
18924
18925    fn save_buffers_for_ranges_if_needed(
18926        &mut self,
18927        ranges: &[Range<Anchor>],
18928        cx: &mut Context<Editor>,
18929    ) -> Task<Result<()>> {
18930        let multibuffer = self.buffer.read(cx);
18931        let snapshot = multibuffer.read(cx);
18932        let buffer_ids: HashSet<_> = ranges
18933            .iter()
18934            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18935            .collect();
18936        drop(snapshot);
18937
18938        let mut buffers = HashSet::default();
18939        for buffer_id in buffer_ids {
18940            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18941                let buffer = buffer_entity.read(cx);
18942                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18943                {
18944                    buffers.insert(buffer_entity);
18945                }
18946            }
18947        }
18948
18949        if let Some(project) = &self.project {
18950            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18951        } else {
18952            Task::ready(Ok(()))
18953        }
18954    }
18955
18956    fn do_stage_or_unstage_and_next(
18957        &mut self,
18958        stage: bool,
18959        window: &mut Window,
18960        cx: &mut Context<Self>,
18961    ) {
18962        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18963
18964        if ranges.iter().any(|range| range.start != range.end) {
18965            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18966            return;
18967        }
18968
18969        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18970        let snapshot = self.snapshot(window, cx);
18971        let position = self
18972            .selections
18973            .newest::<Point>(&snapshot.display_snapshot)
18974            .head();
18975        let mut row = snapshot
18976            .buffer_snapshot()
18977            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18978            .find(|hunk| hunk.row_range.start.0 > position.row)
18979            .map(|hunk| hunk.row_range.start);
18980
18981        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18982        // Outside of the project diff editor, wrap around to the beginning.
18983        if !all_diff_hunks_expanded {
18984            row = row.or_else(|| {
18985                snapshot
18986                    .buffer_snapshot()
18987                    .diff_hunks_in_range(Point::zero()..position)
18988                    .find(|hunk| hunk.row_range.end.0 < position.row)
18989                    .map(|hunk| hunk.row_range.start)
18990            });
18991        }
18992
18993        if let Some(row) = row {
18994            let destination = Point::new(row.0, 0);
18995            let autoscroll = Autoscroll::center();
18996
18997            self.unfold_ranges(&[destination..destination], false, false, cx);
18998            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18999                s.select_ranges([destination..destination]);
19000            });
19001        }
19002    }
19003
19004    fn do_stage_or_unstage(
19005        &self,
19006        stage: bool,
19007        buffer_id: BufferId,
19008        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19009        cx: &mut App,
19010    ) -> Option<()> {
19011        let project = self.project()?;
19012        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19013        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19014        let buffer_snapshot = buffer.read(cx).snapshot();
19015        let file_exists = buffer_snapshot
19016            .file()
19017            .is_some_and(|file| file.disk_state().exists());
19018        diff.update(cx, |diff, cx| {
19019            diff.stage_or_unstage_hunks(
19020                stage,
19021                &hunks
19022                    .map(|hunk| buffer_diff::DiffHunk {
19023                        buffer_range: hunk.buffer_range,
19024                        diff_base_byte_range: hunk.diff_base_byte_range,
19025                        secondary_status: hunk.secondary_status,
19026                        range: Point::zero()..Point::zero(), // unused
19027                    })
19028                    .collect::<Vec<_>>(),
19029                &buffer_snapshot,
19030                file_exists,
19031                cx,
19032            )
19033        });
19034        None
19035    }
19036
19037    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19038        let ranges: Vec<_> = self
19039            .selections
19040            .disjoint_anchors()
19041            .iter()
19042            .map(|s| s.range())
19043            .collect();
19044        self.buffer
19045            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19046    }
19047
19048    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19049        self.buffer.update(cx, |buffer, cx| {
19050            let ranges = vec![Anchor::min()..Anchor::max()];
19051            if !buffer.all_diff_hunks_expanded()
19052                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19053            {
19054                buffer.collapse_diff_hunks(ranges, cx);
19055                true
19056            } else {
19057                false
19058            }
19059        })
19060    }
19061
19062    fn toggle_diff_hunks_in_ranges(
19063        &mut self,
19064        ranges: Vec<Range<Anchor>>,
19065        cx: &mut Context<Editor>,
19066    ) {
19067        self.buffer.update(cx, |buffer, cx| {
19068            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19069            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19070        })
19071    }
19072
19073    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19074        self.buffer.update(cx, |buffer, cx| {
19075            let snapshot = buffer.snapshot(cx);
19076            let excerpt_id = range.end.excerpt_id;
19077            let point_range = range.to_point(&snapshot);
19078            let expand = !buffer.single_hunk_is_expanded(range, cx);
19079            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19080        })
19081    }
19082
19083    pub(crate) fn apply_all_diff_hunks(
19084        &mut self,
19085        _: &ApplyAllDiffHunks,
19086        window: &mut Window,
19087        cx: &mut Context<Self>,
19088    ) {
19089        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19090
19091        let buffers = self.buffer.read(cx).all_buffers();
19092        for branch_buffer in buffers {
19093            branch_buffer.update(cx, |branch_buffer, cx| {
19094                branch_buffer.merge_into_base(Vec::new(), cx);
19095            });
19096        }
19097
19098        if let Some(project) = self.project.clone() {
19099            self.save(
19100                SaveOptions {
19101                    format: true,
19102                    autosave: false,
19103                },
19104                project,
19105                window,
19106                cx,
19107            )
19108            .detach_and_log_err(cx);
19109        }
19110    }
19111
19112    pub(crate) fn apply_selected_diff_hunks(
19113        &mut self,
19114        _: &ApplyDiffHunk,
19115        window: &mut Window,
19116        cx: &mut Context<Self>,
19117    ) {
19118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19119        let snapshot = self.snapshot(window, cx);
19120        let hunks = snapshot.hunks_for_ranges(
19121            self.selections
19122                .all(&snapshot.display_snapshot)
19123                .into_iter()
19124                .map(|selection| selection.range()),
19125        );
19126        let mut ranges_by_buffer = HashMap::default();
19127        self.transact(window, cx, |editor, _window, cx| {
19128            for hunk in hunks {
19129                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19130                    ranges_by_buffer
19131                        .entry(buffer.clone())
19132                        .or_insert_with(Vec::new)
19133                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19134                }
19135            }
19136
19137            for (buffer, ranges) in ranges_by_buffer {
19138                buffer.update(cx, |buffer, cx| {
19139                    buffer.merge_into_base(ranges, cx);
19140                });
19141            }
19142        });
19143
19144        if let Some(project) = self.project.clone() {
19145            self.save(
19146                SaveOptions {
19147                    format: true,
19148                    autosave: false,
19149                },
19150                project,
19151                window,
19152                cx,
19153            )
19154            .detach_and_log_err(cx);
19155        }
19156    }
19157
19158    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19159        if hovered != self.gutter_hovered {
19160            self.gutter_hovered = hovered;
19161            cx.notify();
19162        }
19163    }
19164
19165    pub fn insert_blocks(
19166        &mut self,
19167        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19168        autoscroll: Option<Autoscroll>,
19169        cx: &mut Context<Self>,
19170    ) -> Vec<CustomBlockId> {
19171        let blocks = self
19172            .display_map
19173            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19174        if let Some(autoscroll) = autoscroll {
19175            self.request_autoscroll(autoscroll, cx);
19176        }
19177        cx.notify();
19178        blocks
19179    }
19180
19181    pub fn resize_blocks(
19182        &mut self,
19183        heights: HashMap<CustomBlockId, u32>,
19184        autoscroll: Option<Autoscroll>,
19185        cx: &mut Context<Self>,
19186    ) {
19187        self.display_map
19188            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19189        if let Some(autoscroll) = autoscroll {
19190            self.request_autoscroll(autoscroll, cx);
19191        }
19192        cx.notify();
19193    }
19194
19195    pub fn replace_blocks(
19196        &mut self,
19197        renderers: HashMap<CustomBlockId, RenderBlock>,
19198        autoscroll: Option<Autoscroll>,
19199        cx: &mut Context<Self>,
19200    ) {
19201        self.display_map
19202            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19203        if let Some(autoscroll) = autoscroll {
19204            self.request_autoscroll(autoscroll, cx);
19205        }
19206        cx.notify();
19207    }
19208
19209    pub fn remove_blocks(
19210        &mut self,
19211        block_ids: HashSet<CustomBlockId>,
19212        autoscroll: Option<Autoscroll>,
19213        cx: &mut Context<Self>,
19214    ) {
19215        self.display_map.update(cx, |display_map, cx| {
19216            display_map.remove_blocks(block_ids, cx)
19217        });
19218        if let Some(autoscroll) = autoscroll {
19219            self.request_autoscroll(autoscroll, cx);
19220        }
19221        cx.notify();
19222    }
19223
19224    pub fn row_for_block(
19225        &self,
19226        block_id: CustomBlockId,
19227        cx: &mut Context<Self>,
19228    ) -> Option<DisplayRow> {
19229        self.display_map
19230            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19231    }
19232
19233    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19234        self.focused_block = Some(focused_block);
19235    }
19236
19237    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19238        self.focused_block.take()
19239    }
19240
19241    pub fn insert_creases(
19242        &mut self,
19243        creases: impl IntoIterator<Item = Crease<Anchor>>,
19244        cx: &mut Context<Self>,
19245    ) -> Vec<CreaseId> {
19246        self.display_map
19247            .update(cx, |map, cx| map.insert_creases(creases, cx))
19248    }
19249
19250    pub fn remove_creases(
19251        &mut self,
19252        ids: impl IntoIterator<Item = CreaseId>,
19253        cx: &mut Context<Self>,
19254    ) -> Vec<(CreaseId, Range<Anchor>)> {
19255        self.display_map
19256            .update(cx, |map, cx| map.remove_creases(ids, cx))
19257    }
19258
19259    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19260        self.display_map
19261            .update(cx, |map, cx| map.snapshot(cx))
19262            .longest_row()
19263    }
19264
19265    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19266        self.display_map
19267            .update(cx, |map, cx| map.snapshot(cx))
19268            .max_point()
19269    }
19270
19271    pub fn text(&self, cx: &App) -> String {
19272        self.buffer.read(cx).read(cx).text()
19273    }
19274
19275    pub fn is_empty(&self, cx: &App) -> bool {
19276        self.buffer.read(cx).read(cx).is_empty()
19277    }
19278
19279    pub fn text_option(&self, cx: &App) -> Option<String> {
19280        let text = self.text(cx);
19281        let text = text.trim();
19282
19283        if text.is_empty() {
19284            return None;
19285        }
19286
19287        Some(text.to_string())
19288    }
19289
19290    pub fn set_text(
19291        &mut self,
19292        text: impl Into<Arc<str>>,
19293        window: &mut Window,
19294        cx: &mut Context<Self>,
19295    ) {
19296        self.transact(window, cx, |this, _, cx| {
19297            this.buffer
19298                .read(cx)
19299                .as_singleton()
19300                .expect("you can only call set_text on editors for singleton buffers")
19301                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19302        });
19303    }
19304
19305    pub fn display_text(&self, cx: &mut App) -> String {
19306        self.display_map
19307            .update(cx, |map, cx| map.snapshot(cx))
19308            .text()
19309    }
19310
19311    fn create_minimap(
19312        &self,
19313        minimap_settings: MinimapSettings,
19314        window: &mut Window,
19315        cx: &mut Context<Self>,
19316    ) -> Option<Entity<Self>> {
19317        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19318            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19319    }
19320
19321    fn initialize_new_minimap(
19322        &self,
19323        minimap_settings: MinimapSettings,
19324        window: &mut Window,
19325        cx: &mut Context<Self>,
19326    ) -> Entity<Self> {
19327        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19328
19329        let mut minimap = Editor::new_internal(
19330            EditorMode::Minimap {
19331                parent: cx.weak_entity(),
19332            },
19333            self.buffer.clone(),
19334            None,
19335            Some(self.display_map.clone()),
19336            window,
19337            cx,
19338        );
19339        minimap.scroll_manager.clone_state(&self.scroll_manager);
19340        minimap.set_text_style_refinement(TextStyleRefinement {
19341            font_size: Some(MINIMAP_FONT_SIZE),
19342            font_weight: Some(MINIMAP_FONT_WEIGHT),
19343            ..Default::default()
19344        });
19345        minimap.update_minimap_configuration(minimap_settings, cx);
19346        cx.new(|_| minimap)
19347    }
19348
19349    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19350        let current_line_highlight = minimap_settings
19351            .current_line_highlight
19352            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19353        self.set_current_line_highlight(Some(current_line_highlight));
19354    }
19355
19356    pub fn minimap(&self) -> Option<&Entity<Self>> {
19357        self.minimap
19358            .as_ref()
19359            .filter(|_| self.minimap_visibility.visible())
19360    }
19361
19362    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19363        let mut wrap_guides = smallvec![];
19364
19365        if self.show_wrap_guides == Some(false) {
19366            return wrap_guides;
19367        }
19368
19369        let settings = self.buffer.read(cx).language_settings(cx);
19370        if settings.show_wrap_guides {
19371            match self.soft_wrap_mode(cx) {
19372                SoftWrap::Column(soft_wrap) => {
19373                    wrap_guides.push((soft_wrap as usize, true));
19374                }
19375                SoftWrap::Bounded(soft_wrap) => {
19376                    wrap_guides.push((soft_wrap as usize, true));
19377                }
19378                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19379            }
19380            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19381        }
19382
19383        wrap_guides
19384    }
19385
19386    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19387        let settings = self.buffer.read(cx).language_settings(cx);
19388        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19389        match mode {
19390            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19391                SoftWrap::None
19392            }
19393            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19394            language_settings::SoftWrap::PreferredLineLength => {
19395                SoftWrap::Column(settings.preferred_line_length)
19396            }
19397            language_settings::SoftWrap::Bounded => {
19398                SoftWrap::Bounded(settings.preferred_line_length)
19399            }
19400        }
19401    }
19402
19403    pub fn set_soft_wrap_mode(
19404        &mut self,
19405        mode: language_settings::SoftWrap,
19406
19407        cx: &mut Context<Self>,
19408    ) {
19409        self.soft_wrap_mode_override = Some(mode);
19410        cx.notify();
19411    }
19412
19413    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19414        self.hard_wrap = hard_wrap;
19415        cx.notify();
19416    }
19417
19418    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19419        self.text_style_refinement = Some(style);
19420    }
19421
19422    /// called by the Element so we know what style we were most recently rendered with.
19423    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19424        // We intentionally do not inform the display map about the minimap style
19425        // so that wrapping is not recalculated and stays consistent for the editor
19426        // and its linked minimap.
19427        if !self.mode.is_minimap() {
19428            let font = style.text.font();
19429            let font_size = style.text.font_size.to_pixels(window.rem_size());
19430            let display_map = self
19431                .placeholder_display_map
19432                .as_ref()
19433                .filter(|_| self.is_empty(cx))
19434                .unwrap_or(&self.display_map);
19435
19436            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19437        }
19438        self.style = Some(style);
19439    }
19440
19441    pub fn style(&self) -> Option<&EditorStyle> {
19442        self.style.as_ref()
19443    }
19444
19445    // Called by the element. This method is not designed to be called outside of the editor
19446    // element's layout code because it does not notify when rewrapping is computed synchronously.
19447    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19448        if self.is_empty(cx) {
19449            self.placeholder_display_map
19450                .as_ref()
19451                .map_or(false, |display_map| {
19452                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19453                })
19454        } else {
19455            self.display_map
19456                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19457        }
19458    }
19459
19460    pub fn set_soft_wrap(&mut self) {
19461        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19462    }
19463
19464    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19465        if self.soft_wrap_mode_override.is_some() {
19466            self.soft_wrap_mode_override.take();
19467        } else {
19468            let soft_wrap = match self.soft_wrap_mode(cx) {
19469                SoftWrap::GitDiff => return,
19470                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19471                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19472                    language_settings::SoftWrap::None
19473                }
19474            };
19475            self.soft_wrap_mode_override = Some(soft_wrap);
19476        }
19477        cx.notify();
19478    }
19479
19480    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19481        let Some(workspace) = self.workspace() else {
19482            return;
19483        };
19484        let fs = workspace.read(cx).app_state().fs.clone();
19485        let current_show = TabBarSettings::get_global(cx).show;
19486        update_settings_file(fs, cx, move |setting, _| {
19487            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19488        });
19489    }
19490
19491    pub fn toggle_indent_guides(
19492        &mut self,
19493        _: &ToggleIndentGuides,
19494        _: &mut Window,
19495        cx: &mut Context<Self>,
19496    ) {
19497        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19498            self.buffer
19499                .read(cx)
19500                .language_settings(cx)
19501                .indent_guides
19502                .enabled
19503        });
19504        self.show_indent_guides = Some(!currently_enabled);
19505        cx.notify();
19506    }
19507
19508    fn should_show_indent_guides(&self) -> Option<bool> {
19509        self.show_indent_guides
19510    }
19511
19512    pub fn toggle_line_numbers(
19513        &mut self,
19514        _: &ToggleLineNumbers,
19515        _: &mut Window,
19516        cx: &mut Context<Self>,
19517    ) {
19518        let mut editor_settings = EditorSettings::get_global(cx).clone();
19519        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19520        EditorSettings::override_global(editor_settings, cx);
19521    }
19522
19523    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19524        if let Some(show_line_numbers) = self.show_line_numbers {
19525            return show_line_numbers;
19526        }
19527        EditorSettings::get_global(cx).gutter.line_numbers
19528    }
19529
19530    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19531        self.use_relative_line_numbers
19532            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19533    }
19534
19535    pub fn toggle_relative_line_numbers(
19536        &mut self,
19537        _: &ToggleRelativeLineNumbers,
19538        _: &mut Window,
19539        cx: &mut Context<Self>,
19540    ) {
19541        let is_relative = self.should_use_relative_line_numbers(cx);
19542        self.set_relative_line_number(Some(!is_relative), cx)
19543    }
19544
19545    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19546        self.use_relative_line_numbers = is_relative;
19547        cx.notify();
19548    }
19549
19550    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19551        self.show_gutter = show_gutter;
19552        cx.notify();
19553    }
19554
19555    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19556        self.show_scrollbars = ScrollbarAxes {
19557            horizontal: show,
19558            vertical: show,
19559        };
19560        cx.notify();
19561    }
19562
19563    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19564        self.show_scrollbars.vertical = show;
19565        cx.notify();
19566    }
19567
19568    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19569        self.show_scrollbars.horizontal = show;
19570        cx.notify();
19571    }
19572
19573    pub fn set_minimap_visibility(
19574        &mut self,
19575        minimap_visibility: MinimapVisibility,
19576        window: &mut Window,
19577        cx: &mut Context<Self>,
19578    ) {
19579        if self.minimap_visibility != minimap_visibility {
19580            if minimap_visibility.visible() && self.minimap.is_none() {
19581                let minimap_settings = EditorSettings::get_global(cx).minimap;
19582                self.minimap =
19583                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19584            }
19585            self.minimap_visibility = minimap_visibility;
19586            cx.notify();
19587        }
19588    }
19589
19590    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19591        self.set_show_scrollbars(false, cx);
19592        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19593    }
19594
19595    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19596        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19597    }
19598
19599    /// Normally the text in full mode and auto height editors is padded on the
19600    /// left side by roughly half a character width for improved hit testing.
19601    ///
19602    /// Use this method to disable this for cases where this is not wanted (e.g.
19603    /// if you want to align the editor text with some other text above or below)
19604    /// or if you want to add this padding to single-line editors.
19605    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19606        self.offset_content = offset_content;
19607        cx.notify();
19608    }
19609
19610    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19611        self.show_line_numbers = Some(show_line_numbers);
19612        cx.notify();
19613    }
19614
19615    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19616        self.disable_expand_excerpt_buttons = true;
19617        cx.notify();
19618    }
19619
19620    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19621        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19622        cx.notify();
19623    }
19624
19625    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19626        self.show_code_actions = Some(show_code_actions);
19627        cx.notify();
19628    }
19629
19630    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19631        self.show_runnables = Some(show_runnables);
19632        cx.notify();
19633    }
19634
19635    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19636        self.show_breakpoints = Some(show_breakpoints);
19637        cx.notify();
19638    }
19639
19640    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19641        if self.display_map.read(cx).masked != masked {
19642            self.display_map.update(cx, |map, _| map.masked = masked);
19643        }
19644        cx.notify()
19645    }
19646
19647    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19648        self.show_wrap_guides = Some(show_wrap_guides);
19649        cx.notify();
19650    }
19651
19652    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19653        self.show_indent_guides = Some(show_indent_guides);
19654        cx.notify();
19655    }
19656
19657    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19658        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19659            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19660                && let Some(dir) = file.abs_path(cx).parent()
19661            {
19662                return Some(dir.to_owned());
19663            }
19664        }
19665
19666        None
19667    }
19668
19669    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19670        self.active_excerpt(cx)?
19671            .1
19672            .read(cx)
19673            .file()
19674            .and_then(|f| f.as_local())
19675    }
19676
19677    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19678        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19679            let buffer = buffer.read(cx);
19680            if let Some(project_path) = buffer.project_path(cx) {
19681                let project = self.project()?.read(cx);
19682                project.absolute_path(&project_path, cx)
19683            } else {
19684                buffer
19685                    .file()
19686                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19687            }
19688        })
19689    }
19690
19691    pub fn reveal_in_finder(
19692        &mut self,
19693        _: &RevealInFileManager,
19694        _window: &mut Window,
19695        cx: &mut Context<Self>,
19696    ) {
19697        if let Some(target) = self.target_file(cx) {
19698            cx.reveal_path(&target.abs_path(cx));
19699        }
19700    }
19701
19702    pub fn copy_path(
19703        &mut self,
19704        _: &zed_actions::workspace::CopyPath,
19705        _window: &mut Window,
19706        cx: &mut Context<Self>,
19707    ) {
19708        if let Some(path) = self.target_file_abs_path(cx)
19709            && let Some(path) = path.to_str()
19710        {
19711            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19712        } else {
19713            cx.propagate();
19714        }
19715    }
19716
19717    pub fn copy_relative_path(
19718        &mut self,
19719        _: &zed_actions::workspace::CopyRelativePath,
19720        _window: &mut Window,
19721        cx: &mut Context<Self>,
19722    ) {
19723        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19724            let project = self.project()?.read(cx);
19725            let path = buffer.read(cx).file()?.path();
19726            let path = path.display(project.path_style(cx));
19727            Some(path)
19728        }) {
19729            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19730        } else {
19731            cx.propagate();
19732        }
19733    }
19734
19735    /// Returns the project path for the editor's buffer, if any buffer is
19736    /// opened in the editor.
19737    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19738        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19739            buffer.read(cx).project_path(cx)
19740        } else {
19741            None
19742        }
19743    }
19744
19745    // Returns true if the editor handled a go-to-line request
19746    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19747        maybe!({
19748            let breakpoint_store = self.breakpoint_store.as_ref()?;
19749
19750            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19751            else {
19752                self.clear_row_highlights::<ActiveDebugLine>();
19753                return None;
19754            };
19755
19756            let position = active_stack_frame.position;
19757            let buffer_id = position.buffer_id?;
19758            let snapshot = self
19759                .project
19760                .as_ref()?
19761                .read(cx)
19762                .buffer_for_id(buffer_id, cx)?
19763                .read(cx)
19764                .snapshot();
19765
19766            let mut handled = false;
19767            for (id, ExcerptRange { context, .. }) in
19768                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19769            {
19770                if context.start.cmp(&position, &snapshot).is_ge()
19771                    || context.end.cmp(&position, &snapshot).is_lt()
19772                {
19773                    continue;
19774                }
19775                let snapshot = self.buffer.read(cx).snapshot(cx);
19776                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19777
19778                handled = true;
19779                self.clear_row_highlights::<ActiveDebugLine>();
19780
19781                self.go_to_line::<ActiveDebugLine>(
19782                    multibuffer_anchor,
19783                    Some(cx.theme().colors().editor_debugger_active_line_background),
19784                    window,
19785                    cx,
19786                );
19787
19788                cx.notify();
19789            }
19790
19791            handled.then_some(())
19792        })
19793        .is_some()
19794    }
19795
19796    pub fn copy_file_name_without_extension(
19797        &mut self,
19798        _: &CopyFileNameWithoutExtension,
19799        _: &mut Window,
19800        cx: &mut Context<Self>,
19801    ) {
19802        if let Some(file) = self.target_file(cx)
19803            && let Some(file_stem) = file.path().file_stem()
19804        {
19805            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19806        }
19807    }
19808
19809    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19810        if let Some(file) = self.target_file(cx)
19811            && let Some(name) = file.path().file_name()
19812        {
19813            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19814        }
19815    }
19816
19817    pub fn toggle_git_blame(
19818        &mut self,
19819        _: &::git::Blame,
19820        window: &mut Window,
19821        cx: &mut Context<Self>,
19822    ) {
19823        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19824
19825        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19826            self.start_git_blame(true, window, cx);
19827        }
19828
19829        cx.notify();
19830    }
19831
19832    pub fn toggle_git_blame_inline(
19833        &mut self,
19834        _: &ToggleGitBlameInline,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        self.toggle_git_blame_inline_internal(true, window, cx);
19839        cx.notify();
19840    }
19841
19842    pub fn open_git_blame_commit(
19843        &mut self,
19844        _: &OpenGitBlameCommit,
19845        window: &mut Window,
19846        cx: &mut Context<Self>,
19847    ) {
19848        self.open_git_blame_commit_internal(window, cx);
19849    }
19850
19851    fn open_git_blame_commit_internal(
19852        &mut self,
19853        window: &mut Window,
19854        cx: &mut Context<Self>,
19855    ) -> Option<()> {
19856        let blame = self.blame.as_ref()?;
19857        let snapshot = self.snapshot(window, cx);
19858        let cursor = self
19859            .selections
19860            .newest::<Point>(&snapshot.display_snapshot)
19861            .head();
19862        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19863        let (_, blame_entry) = blame
19864            .update(cx, |blame, cx| {
19865                blame
19866                    .blame_for_rows(
19867                        &[RowInfo {
19868                            buffer_id: Some(buffer.remote_id()),
19869                            buffer_row: Some(point.row),
19870                            ..Default::default()
19871                        }],
19872                        cx,
19873                    )
19874                    .next()
19875            })
19876            .flatten()?;
19877        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19878        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19879        let workspace = self.workspace()?.downgrade();
19880        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19881        None
19882    }
19883
19884    pub fn git_blame_inline_enabled(&self) -> bool {
19885        self.git_blame_inline_enabled
19886    }
19887
19888    pub fn toggle_selection_menu(
19889        &mut self,
19890        _: &ToggleSelectionMenu,
19891        _: &mut Window,
19892        cx: &mut Context<Self>,
19893    ) {
19894        self.show_selection_menu = self
19895            .show_selection_menu
19896            .map(|show_selections_menu| !show_selections_menu)
19897            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19898
19899        cx.notify();
19900    }
19901
19902    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19903        self.show_selection_menu
19904            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19905    }
19906
19907    fn start_git_blame(
19908        &mut self,
19909        user_triggered: bool,
19910        window: &mut Window,
19911        cx: &mut Context<Self>,
19912    ) {
19913        if let Some(project) = self.project() {
19914            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19915                && buffer.read(cx).file().is_none()
19916            {
19917                return;
19918            }
19919
19920            let focused = self.focus_handle(cx).contains_focused(window, cx);
19921
19922            let project = project.clone();
19923            let blame = cx
19924                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19925            self.blame_subscription =
19926                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19927            self.blame = Some(blame);
19928        }
19929    }
19930
19931    fn toggle_git_blame_inline_internal(
19932        &mut self,
19933        user_triggered: bool,
19934        window: &mut Window,
19935        cx: &mut Context<Self>,
19936    ) {
19937        if self.git_blame_inline_enabled {
19938            self.git_blame_inline_enabled = false;
19939            self.show_git_blame_inline = false;
19940            self.show_git_blame_inline_delay_task.take();
19941        } else {
19942            self.git_blame_inline_enabled = true;
19943            self.start_git_blame_inline(user_triggered, window, cx);
19944        }
19945
19946        cx.notify();
19947    }
19948
19949    fn start_git_blame_inline(
19950        &mut self,
19951        user_triggered: bool,
19952        window: &mut Window,
19953        cx: &mut Context<Self>,
19954    ) {
19955        self.start_git_blame(user_triggered, window, cx);
19956
19957        if ProjectSettings::get_global(cx)
19958            .git
19959            .inline_blame_delay()
19960            .is_some()
19961        {
19962            self.start_inline_blame_timer(window, cx);
19963        } else {
19964            self.show_git_blame_inline = true
19965        }
19966    }
19967
19968    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19969        self.blame.as_ref()
19970    }
19971
19972    pub fn show_git_blame_gutter(&self) -> bool {
19973        self.show_git_blame_gutter
19974    }
19975
19976    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19977        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19978    }
19979
19980    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19981        self.show_git_blame_inline
19982            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19983            && !self.newest_selection_head_on_empty_line(cx)
19984            && self.has_blame_entries(cx)
19985    }
19986
19987    fn has_blame_entries(&self, cx: &App) -> bool {
19988        self.blame()
19989            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19990    }
19991
19992    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19993        let cursor_anchor = self.selections.newest_anchor().head();
19994
19995        let snapshot = self.buffer.read(cx).snapshot(cx);
19996        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19997
19998        snapshot.line_len(buffer_row) == 0
19999    }
20000
20001    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20002        let buffer_and_selection = maybe!({
20003            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20004            let selection_range = selection.range();
20005
20006            let multi_buffer = self.buffer().read(cx);
20007            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20008            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20009
20010            let (buffer, range, _) = if selection.reversed {
20011                buffer_ranges.first()
20012            } else {
20013                buffer_ranges.last()
20014            }?;
20015
20016            let selection = text::ToPoint::to_point(&range.start, buffer).row
20017                ..text::ToPoint::to_point(&range.end, buffer).row;
20018            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20019        });
20020
20021        let Some((buffer, selection)) = buffer_and_selection else {
20022            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20023        };
20024
20025        let Some(project) = self.project() else {
20026            return Task::ready(Err(anyhow!("editor does not have project")));
20027        };
20028
20029        project.update(cx, |project, cx| {
20030            project.get_permalink_to_line(&buffer, selection, cx)
20031        })
20032    }
20033
20034    pub fn copy_permalink_to_line(
20035        &mut self,
20036        _: &CopyPermalinkToLine,
20037        window: &mut Window,
20038        cx: &mut Context<Self>,
20039    ) {
20040        let permalink_task = self.get_permalink_to_line(cx);
20041        let workspace = self.workspace();
20042
20043        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20044            Ok(permalink) => {
20045                cx.update(|_, cx| {
20046                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20047                })
20048                .ok();
20049            }
20050            Err(err) => {
20051                let message = format!("Failed to copy permalink: {err}");
20052
20053                anyhow::Result::<()>::Err(err).log_err();
20054
20055                if let Some(workspace) = workspace {
20056                    workspace
20057                        .update_in(cx, |workspace, _, cx| {
20058                            struct CopyPermalinkToLine;
20059
20060                            workspace.show_toast(
20061                                Toast::new(
20062                                    NotificationId::unique::<CopyPermalinkToLine>(),
20063                                    message,
20064                                ),
20065                                cx,
20066                            )
20067                        })
20068                        .ok();
20069                }
20070            }
20071        })
20072        .detach();
20073    }
20074
20075    pub fn copy_file_location(
20076        &mut self,
20077        _: &CopyFileLocation,
20078        _: &mut Window,
20079        cx: &mut Context<Self>,
20080    ) {
20081        let selection = self
20082            .selections
20083            .newest::<Point>(&self.display_snapshot(cx))
20084            .start
20085            .row
20086            + 1;
20087        if let Some(file) = self.target_file(cx) {
20088            let path = file.path().display(file.path_style(cx));
20089            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20090        }
20091    }
20092
20093    pub fn open_permalink_to_line(
20094        &mut self,
20095        _: &OpenPermalinkToLine,
20096        window: &mut Window,
20097        cx: &mut Context<Self>,
20098    ) {
20099        let permalink_task = self.get_permalink_to_line(cx);
20100        let workspace = self.workspace();
20101
20102        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20103            Ok(permalink) => {
20104                cx.update(|_, cx| {
20105                    cx.open_url(permalink.as_ref());
20106                })
20107                .ok();
20108            }
20109            Err(err) => {
20110                let message = format!("Failed to open permalink: {err}");
20111
20112                anyhow::Result::<()>::Err(err).log_err();
20113
20114                if let Some(workspace) = workspace {
20115                    workspace
20116                        .update(cx, |workspace, cx| {
20117                            struct OpenPermalinkToLine;
20118
20119                            workspace.show_toast(
20120                                Toast::new(
20121                                    NotificationId::unique::<OpenPermalinkToLine>(),
20122                                    message,
20123                                ),
20124                                cx,
20125                            )
20126                        })
20127                        .ok();
20128                }
20129            }
20130        })
20131        .detach();
20132    }
20133
20134    pub fn insert_uuid_v4(
20135        &mut self,
20136        _: &InsertUuidV4,
20137        window: &mut Window,
20138        cx: &mut Context<Self>,
20139    ) {
20140        self.insert_uuid(UuidVersion::V4, window, cx);
20141    }
20142
20143    pub fn insert_uuid_v7(
20144        &mut self,
20145        _: &InsertUuidV7,
20146        window: &mut Window,
20147        cx: &mut Context<Self>,
20148    ) {
20149        self.insert_uuid(UuidVersion::V7, window, cx);
20150    }
20151
20152    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20153        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20154        self.transact(window, cx, |this, window, cx| {
20155            let edits = this
20156                .selections
20157                .all::<Point>(&this.display_snapshot(cx))
20158                .into_iter()
20159                .map(|selection| {
20160                    let uuid = match version {
20161                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20162                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20163                    };
20164
20165                    (selection.range(), uuid.to_string())
20166                });
20167            this.edit(edits, cx);
20168            this.refresh_edit_prediction(true, false, window, cx);
20169        });
20170    }
20171
20172    pub fn open_selections_in_multibuffer(
20173        &mut self,
20174        _: &OpenSelectionsInMultibuffer,
20175        window: &mut Window,
20176        cx: &mut Context<Self>,
20177    ) {
20178        let multibuffer = self.buffer.read(cx);
20179
20180        let Some(buffer) = multibuffer.as_singleton() else {
20181            return;
20182        };
20183
20184        let Some(workspace) = self.workspace() else {
20185            return;
20186        };
20187
20188        let title = multibuffer.title(cx).to_string();
20189
20190        let locations = self
20191            .selections
20192            .all_anchors(cx)
20193            .iter()
20194            .map(|selection| {
20195                (
20196                    buffer.clone(),
20197                    (selection.start.text_anchor..selection.end.text_anchor)
20198                        .to_point(buffer.read(cx)),
20199                )
20200            })
20201            .into_group_map();
20202
20203        cx.spawn_in(window, async move |_, cx| {
20204            workspace.update_in(cx, |workspace, window, cx| {
20205                Self::open_locations_in_multibuffer(
20206                    workspace,
20207                    locations,
20208                    format!("Selections for '{title}'"),
20209                    false,
20210                    MultibufferSelectionMode::All,
20211                    window,
20212                    cx,
20213                );
20214            })
20215        })
20216        .detach();
20217    }
20218
20219    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20220    /// last highlight added will be used.
20221    ///
20222    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20223    pub fn highlight_rows<T: 'static>(
20224        &mut self,
20225        range: Range<Anchor>,
20226        color: Hsla,
20227        options: RowHighlightOptions,
20228        cx: &mut Context<Self>,
20229    ) {
20230        let snapshot = self.buffer().read(cx).snapshot(cx);
20231        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20232        let ix = row_highlights.binary_search_by(|highlight| {
20233            Ordering::Equal
20234                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20235                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20236        });
20237
20238        if let Err(mut ix) = ix {
20239            let index = post_inc(&mut self.highlight_order);
20240
20241            // If this range intersects with the preceding highlight, then merge it with
20242            // the preceding highlight. Otherwise insert a new highlight.
20243            let mut merged = false;
20244            if ix > 0 {
20245                let prev_highlight = &mut row_highlights[ix - 1];
20246                if prev_highlight
20247                    .range
20248                    .end
20249                    .cmp(&range.start, &snapshot)
20250                    .is_ge()
20251                {
20252                    ix -= 1;
20253                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20254                        prev_highlight.range.end = range.end;
20255                    }
20256                    merged = true;
20257                    prev_highlight.index = index;
20258                    prev_highlight.color = color;
20259                    prev_highlight.options = options;
20260                }
20261            }
20262
20263            if !merged {
20264                row_highlights.insert(
20265                    ix,
20266                    RowHighlight {
20267                        range,
20268                        index,
20269                        color,
20270                        options,
20271                        type_id: TypeId::of::<T>(),
20272                    },
20273                );
20274            }
20275
20276            // If any of the following highlights intersect with this one, merge them.
20277            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20278                let highlight = &row_highlights[ix];
20279                if next_highlight
20280                    .range
20281                    .start
20282                    .cmp(&highlight.range.end, &snapshot)
20283                    .is_le()
20284                {
20285                    if next_highlight
20286                        .range
20287                        .end
20288                        .cmp(&highlight.range.end, &snapshot)
20289                        .is_gt()
20290                    {
20291                        row_highlights[ix].range.end = next_highlight.range.end;
20292                    }
20293                    row_highlights.remove(ix + 1);
20294                } else {
20295                    break;
20296                }
20297            }
20298        }
20299    }
20300
20301    /// Remove any highlighted row ranges of the given type that intersect the
20302    /// given ranges.
20303    pub fn remove_highlighted_rows<T: 'static>(
20304        &mut self,
20305        ranges_to_remove: Vec<Range<Anchor>>,
20306        cx: &mut Context<Self>,
20307    ) {
20308        let snapshot = self.buffer().read(cx).snapshot(cx);
20309        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20310        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20311        row_highlights.retain(|highlight| {
20312            while let Some(range_to_remove) = ranges_to_remove.peek() {
20313                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20314                    Ordering::Less | Ordering::Equal => {
20315                        ranges_to_remove.next();
20316                    }
20317                    Ordering::Greater => {
20318                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20319                            Ordering::Less | Ordering::Equal => {
20320                                return false;
20321                            }
20322                            Ordering::Greater => break,
20323                        }
20324                    }
20325                }
20326            }
20327
20328            true
20329        })
20330    }
20331
20332    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20333    pub fn clear_row_highlights<T: 'static>(&mut self) {
20334        self.highlighted_rows.remove(&TypeId::of::<T>());
20335    }
20336
20337    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20338    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20339        self.highlighted_rows
20340            .get(&TypeId::of::<T>())
20341            .map_or(&[] as &[_], |vec| vec.as_slice())
20342            .iter()
20343            .map(|highlight| (highlight.range.clone(), highlight.color))
20344    }
20345
20346    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20347    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20348    /// Allows to ignore certain kinds of highlights.
20349    pub fn highlighted_display_rows(
20350        &self,
20351        window: &mut Window,
20352        cx: &mut App,
20353    ) -> BTreeMap<DisplayRow, LineHighlight> {
20354        let snapshot = self.snapshot(window, cx);
20355        let mut used_highlight_orders = HashMap::default();
20356        self.highlighted_rows
20357            .iter()
20358            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20359            .fold(
20360                BTreeMap::<DisplayRow, LineHighlight>::new(),
20361                |mut unique_rows, highlight| {
20362                    let start = highlight.range.start.to_display_point(&snapshot);
20363                    let end = highlight.range.end.to_display_point(&snapshot);
20364                    let start_row = start.row().0;
20365                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20366                        && end.column() == 0
20367                    {
20368                        end.row().0.saturating_sub(1)
20369                    } else {
20370                        end.row().0
20371                    };
20372                    for row in start_row..=end_row {
20373                        let used_index =
20374                            used_highlight_orders.entry(row).or_insert(highlight.index);
20375                        if highlight.index >= *used_index {
20376                            *used_index = highlight.index;
20377                            unique_rows.insert(
20378                                DisplayRow(row),
20379                                LineHighlight {
20380                                    include_gutter: highlight.options.include_gutter,
20381                                    border: None,
20382                                    background: highlight.color.into(),
20383                                    type_id: Some(highlight.type_id),
20384                                },
20385                            );
20386                        }
20387                    }
20388                    unique_rows
20389                },
20390            )
20391    }
20392
20393    pub fn highlighted_display_row_for_autoscroll(
20394        &self,
20395        snapshot: &DisplaySnapshot,
20396    ) -> Option<DisplayRow> {
20397        self.highlighted_rows
20398            .values()
20399            .flat_map(|highlighted_rows| highlighted_rows.iter())
20400            .filter_map(|highlight| {
20401                if highlight.options.autoscroll {
20402                    Some(highlight.range.start.to_display_point(snapshot).row())
20403                } else {
20404                    None
20405                }
20406            })
20407            .min()
20408    }
20409
20410    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20411        self.highlight_background::<SearchWithinRange>(
20412            ranges,
20413            |colors| colors.colors().editor_document_highlight_read_background,
20414            cx,
20415        )
20416    }
20417
20418    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20419        self.breadcrumb_header = Some(new_header);
20420    }
20421
20422    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20423        self.clear_background_highlights::<SearchWithinRange>(cx);
20424    }
20425
20426    pub fn highlight_background<T: 'static>(
20427        &mut self,
20428        ranges: &[Range<Anchor>],
20429        color_fetcher: fn(&Theme) -> Hsla,
20430        cx: &mut Context<Self>,
20431    ) {
20432        self.background_highlights.insert(
20433            HighlightKey::Type(TypeId::of::<T>()),
20434            (color_fetcher, Arc::from(ranges)),
20435        );
20436        self.scrollbar_marker_state.dirty = true;
20437        cx.notify();
20438    }
20439
20440    pub fn highlight_background_key<T: 'static>(
20441        &mut self,
20442        key: usize,
20443        ranges: &[Range<Anchor>],
20444        color_fetcher: fn(&Theme) -> Hsla,
20445        cx: &mut Context<Self>,
20446    ) {
20447        self.background_highlights.insert(
20448            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20449            (color_fetcher, Arc::from(ranges)),
20450        );
20451        self.scrollbar_marker_state.dirty = true;
20452        cx.notify();
20453    }
20454
20455    pub fn clear_background_highlights<T: 'static>(
20456        &mut self,
20457        cx: &mut Context<Self>,
20458    ) -> Option<BackgroundHighlight> {
20459        let text_highlights = self
20460            .background_highlights
20461            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20462        if !text_highlights.1.is_empty() {
20463            self.scrollbar_marker_state.dirty = true;
20464            cx.notify();
20465        }
20466        Some(text_highlights)
20467    }
20468
20469    pub fn highlight_gutter<T: 'static>(
20470        &mut self,
20471        ranges: impl Into<Vec<Range<Anchor>>>,
20472        color_fetcher: fn(&App) -> Hsla,
20473        cx: &mut Context<Self>,
20474    ) {
20475        self.gutter_highlights
20476            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20477        cx.notify();
20478    }
20479
20480    pub fn clear_gutter_highlights<T: 'static>(
20481        &mut self,
20482        cx: &mut Context<Self>,
20483    ) -> Option<GutterHighlight> {
20484        cx.notify();
20485        self.gutter_highlights.remove(&TypeId::of::<T>())
20486    }
20487
20488    pub fn insert_gutter_highlight<T: 'static>(
20489        &mut self,
20490        range: Range<Anchor>,
20491        color_fetcher: fn(&App) -> Hsla,
20492        cx: &mut Context<Self>,
20493    ) {
20494        let snapshot = self.buffer().read(cx).snapshot(cx);
20495        let mut highlights = self
20496            .gutter_highlights
20497            .remove(&TypeId::of::<T>())
20498            .map(|(_, highlights)| highlights)
20499            .unwrap_or_default();
20500        let ix = highlights.binary_search_by(|highlight| {
20501            Ordering::Equal
20502                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20503                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20504        });
20505        if let Err(ix) = ix {
20506            highlights.insert(ix, range);
20507        }
20508        self.gutter_highlights
20509            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20510    }
20511
20512    pub fn remove_gutter_highlights<T: 'static>(
20513        &mut self,
20514        ranges_to_remove: Vec<Range<Anchor>>,
20515        cx: &mut Context<Self>,
20516    ) {
20517        let snapshot = self.buffer().read(cx).snapshot(cx);
20518        let Some((color_fetcher, mut gutter_highlights)) =
20519            self.gutter_highlights.remove(&TypeId::of::<T>())
20520        else {
20521            return;
20522        };
20523        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20524        gutter_highlights.retain(|highlight| {
20525            while let Some(range_to_remove) = ranges_to_remove.peek() {
20526                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20527                    Ordering::Less | Ordering::Equal => {
20528                        ranges_to_remove.next();
20529                    }
20530                    Ordering::Greater => {
20531                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20532                            Ordering::Less | Ordering::Equal => {
20533                                return false;
20534                            }
20535                            Ordering::Greater => break,
20536                        }
20537                    }
20538                }
20539            }
20540
20541            true
20542        });
20543        self.gutter_highlights
20544            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20545    }
20546
20547    #[cfg(feature = "test-support")]
20548    pub fn all_text_highlights(
20549        &self,
20550        window: &mut Window,
20551        cx: &mut Context<Self>,
20552    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20553        let snapshot = self.snapshot(window, cx);
20554        self.display_map.update(cx, |display_map, _| {
20555            display_map
20556                .all_text_highlights()
20557                .map(|highlight| {
20558                    let (style, ranges) = highlight.as_ref();
20559                    (
20560                        *style,
20561                        ranges
20562                            .iter()
20563                            .map(|range| range.clone().to_display_points(&snapshot))
20564                            .collect(),
20565                    )
20566                })
20567                .collect()
20568        })
20569    }
20570
20571    #[cfg(feature = "test-support")]
20572    pub fn all_text_background_highlights(
20573        &self,
20574        window: &mut Window,
20575        cx: &mut Context<Self>,
20576    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20577        let snapshot = self.snapshot(window, cx);
20578        let buffer = &snapshot.buffer_snapshot();
20579        let start = buffer.anchor_before(0);
20580        let end = buffer.anchor_after(buffer.len());
20581        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20582    }
20583
20584    #[cfg(any(test, feature = "test-support"))]
20585    pub fn sorted_background_highlights_in_range(
20586        &self,
20587        search_range: Range<Anchor>,
20588        display_snapshot: &DisplaySnapshot,
20589        theme: &Theme,
20590    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20591        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20592        res.sort_by(|a, b| {
20593            a.0.start
20594                .cmp(&b.0.start)
20595                .then_with(|| a.0.end.cmp(&b.0.end))
20596                .then_with(|| a.1.cmp(&b.1))
20597        });
20598        res
20599    }
20600
20601    #[cfg(feature = "test-support")]
20602    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20603        let snapshot = self.buffer().read(cx).snapshot(cx);
20604
20605        let highlights = self
20606            .background_highlights
20607            .get(&HighlightKey::Type(TypeId::of::<
20608                items::BufferSearchHighlights,
20609            >()));
20610
20611        if let Some((_color, ranges)) = highlights {
20612            ranges
20613                .iter()
20614                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20615                .collect_vec()
20616        } else {
20617            vec![]
20618        }
20619    }
20620
20621    fn document_highlights_for_position<'a>(
20622        &'a self,
20623        position: Anchor,
20624        buffer: &'a MultiBufferSnapshot,
20625    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20626        let read_highlights = self
20627            .background_highlights
20628            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20629            .map(|h| &h.1);
20630        let write_highlights = self
20631            .background_highlights
20632            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20633            .map(|h| &h.1);
20634        let left_position = position.bias_left(buffer);
20635        let right_position = position.bias_right(buffer);
20636        read_highlights
20637            .into_iter()
20638            .chain(write_highlights)
20639            .flat_map(move |ranges| {
20640                let start_ix = match ranges.binary_search_by(|probe| {
20641                    let cmp = probe.end.cmp(&left_position, buffer);
20642                    if cmp.is_ge() {
20643                        Ordering::Greater
20644                    } else {
20645                        Ordering::Less
20646                    }
20647                }) {
20648                    Ok(i) | Err(i) => i,
20649                };
20650
20651                ranges[start_ix..]
20652                    .iter()
20653                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20654            })
20655    }
20656
20657    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20658        self.background_highlights
20659            .get(&HighlightKey::Type(TypeId::of::<T>()))
20660            .is_some_and(|(_, highlights)| !highlights.is_empty())
20661    }
20662
20663    /// Returns all background highlights for a given range.
20664    ///
20665    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20666    pub fn background_highlights_in_range(
20667        &self,
20668        search_range: Range<Anchor>,
20669        display_snapshot: &DisplaySnapshot,
20670        theme: &Theme,
20671    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20672        let mut results = Vec::new();
20673        for (color_fetcher, ranges) in self.background_highlights.values() {
20674            let color = color_fetcher(theme);
20675            let start_ix = match ranges.binary_search_by(|probe| {
20676                let cmp = probe
20677                    .end
20678                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20679                if cmp.is_gt() {
20680                    Ordering::Greater
20681                } else {
20682                    Ordering::Less
20683                }
20684            }) {
20685                Ok(i) | Err(i) => i,
20686            };
20687            for range in &ranges[start_ix..] {
20688                if range
20689                    .start
20690                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20691                    .is_ge()
20692                {
20693                    break;
20694                }
20695
20696                let start = range.start.to_display_point(display_snapshot);
20697                let end = range.end.to_display_point(display_snapshot);
20698                results.push((start..end, color))
20699            }
20700        }
20701        results
20702    }
20703
20704    pub fn gutter_highlights_in_range(
20705        &self,
20706        search_range: Range<Anchor>,
20707        display_snapshot: &DisplaySnapshot,
20708        cx: &App,
20709    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20710        let mut results = Vec::new();
20711        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20712            let color = color_fetcher(cx);
20713            let start_ix = match ranges.binary_search_by(|probe| {
20714                let cmp = probe
20715                    .end
20716                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20717                if cmp.is_gt() {
20718                    Ordering::Greater
20719                } else {
20720                    Ordering::Less
20721                }
20722            }) {
20723                Ok(i) | Err(i) => i,
20724            };
20725            for range in &ranges[start_ix..] {
20726                if range
20727                    .start
20728                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20729                    .is_ge()
20730                {
20731                    break;
20732                }
20733
20734                let start = range.start.to_display_point(display_snapshot);
20735                let end = range.end.to_display_point(display_snapshot);
20736                results.push((start..end, color))
20737            }
20738        }
20739        results
20740    }
20741
20742    /// Get the text ranges corresponding to the redaction query
20743    pub fn redacted_ranges(
20744        &self,
20745        search_range: Range<Anchor>,
20746        display_snapshot: &DisplaySnapshot,
20747        cx: &App,
20748    ) -> Vec<Range<DisplayPoint>> {
20749        display_snapshot
20750            .buffer_snapshot()
20751            .redacted_ranges(search_range, |file| {
20752                if let Some(file) = file {
20753                    file.is_private()
20754                        && EditorSettings::get(
20755                            Some(SettingsLocation {
20756                                worktree_id: file.worktree_id(cx),
20757                                path: file.path().as_ref(),
20758                            }),
20759                            cx,
20760                        )
20761                        .redact_private_values
20762                } else {
20763                    false
20764                }
20765            })
20766            .map(|range| {
20767                range.start.to_display_point(display_snapshot)
20768                    ..range.end.to_display_point(display_snapshot)
20769            })
20770            .collect()
20771    }
20772
20773    pub fn highlight_text_key<T: 'static>(
20774        &mut self,
20775        key: usize,
20776        ranges: Vec<Range<Anchor>>,
20777        style: HighlightStyle,
20778        cx: &mut Context<Self>,
20779    ) {
20780        self.display_map.update(cx, |map, _| {
20781            map.highlight_text(
20782                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20783                ranges,
20784                style,
20785            );
20786        });
20787        cx.notify();
20788    }
20789
20790    pub fn highlight_text<T: 'static>(
20791        &mut self,
20792        ranges: Vec<Range<Anchor>>,
20793        style: HighlightStyle,
20794        cx: &mut Context<Self>,
20795    ) {
20796        self.display_map.update(cx, |map, _| {
20797            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20798        });
20799        cx.notify();
20800    }
20801
20802    pub(crate) fn highlight_inlays<T: 'static>(
20803        &mut self,
20804        highlights: Vec<InlayHighlight>,
20805        style: HighlightStyle,
20806        cx: &mut Context<Self>,
20807    ) {
20808        self.display_map.update(cx, |map, _| {
20809            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20810        });
20811        cx.notify();
20812    }
20813
20814    pub fn text_highlights<'a, T: 'static>(
20815        &'a self,
20816        cx: &'a App,
20817    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20818        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20819    }
20820
20821    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20822        let cleared = self
20823            .display_map
20824            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20825        if cleared {
20826            cx.notify();
20827        }
20828    }
20829
20830    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20831        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20832            && self.focus_handle.is_focused(window)
20833    }
20834
20835    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20836        self.show_cursor_when_unfocused = is_enabled;
20837        cx.notify();
20838    }
20839
20840    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20841        cx.notify();
20842    }
20843
20844    fn on_debug_session_event(
20845        &mut self,
20846        _session: Entity<Session>,
20847        event: &SessionEvent,
20848        cx: &mut Context<Self>,
20849    ) {
20850        if let SessionEvent::InvalidateInlineValue = event {
20851            self.refresh_inline_values(cx);
20852        }
20853    }
20854
20855    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20856        let Some(project) = self.project.clone() else {
20857            return;
20858        };
20859
20860        if !self.inline_value_cache.enabled {
20861            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20862            self.splice_inlays(&inlays, Vec::new(), cx);
20863            return;
20864        }
20865
20866        let current_execution_position = self
20867            .highlighted_rows
20868            .get(&TypeId::of::<ActiveDebugLine>())
20869            .and_then(|lines| lines.last().map(|line| line.range.end));
20870
20871        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20872            let inline_values = editor
20873                .update(cx, |editor, cx| {
20874                    let Some(current_execution_position) = current_execution_position else {
20875                        return Some(Task::ready(Ok(Vec::new())));
20876                    };
20877
20878                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20879                        let snapshot = buffer.snapshot(cx);
20880
20881                        let excerpt = snapshot.excerpt_containing(
20882                            current_execution_position..current_execution_position,
20883                        )?;
20884
20885                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20886                    })?;
20887
20888                    let range =
20889                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20890
20891                    project.inline_values(buffer, range, cx)
20892                })
20893                .ok()
20894                .flatten()?
20895                .await
20896                .context("refreshing debugger inlays")
20897                .log_err()?;
20898
20899            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20900
20901            for (buffer_id, inline_value) in inline_values
20902                .into_iter()
20903                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20904            {
20905                buffer_inline_values
20906                    .entry(buffer_id)
20907                    .or_default()
20908                    .push(inline_value);
20909            }
20910
20911            editor
20912                .update(cx, |editor, cx| {
20913                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20914                    let mut new_inlays = Vec::default();
20915
20916                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20917                        let buffer_id = buffer_snapshot.remote_id();
20918                        buffer_inline_values
20919                            .get(&buffer_id)
20920                            .into_iter()
20921                            .flatten()
20922                            .for_each(|hint| {
20923                                let inlay = Inlay::debugger(
20924                                    post_inc(&mut editor.next_inlay_id),
20925                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20926                                    hint.text(),
20927                                );
20928                                if !inlay.text().chars().contains(&'\n') {
20929                                    new_inlays.push(inlay);
20930                                }
20931                            });
20932                    }
20933
20934                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20935                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20936
20937                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20938                })
20939                .ok()?;
20940            Some(())
20941        });
20942    }
20943
20944    fn on_buffer_event(
20945        &mut self,
20946        multibuffer: &Entity<MultiBuffer>,
20947        event: &multi_buffer::Event,
20948        window: &mut Window,
20949        cx: &mut Context<Self>,
20950    ) {
20951        match event {
20952            multi_buffer::Event::Edited { edited_buffer } => {
20953                self.scrollbar_marker_state.dirty = true;
20954                self.active_indent_guides_state.dirty = true;
20955                self.refresh_active_diagnostics(cx);
20956                self.refresh_code_actions(window, cx);
20957                self.refresh_selected_text_highlights(true, window, cx);
20958                self.refresh_single_line_folds(window, cx);
20959                refresh_matching_bracket_highlights(self, cx);
20960                if self.has_active_edit_prediction() {
20961                    self.update_visible_edit_prediction(window, cx);
20962                }
20963
20964                if let Some(edited_buffer) = edited_buffer {
20965                    if edited_buffer.read(cx).file().is_none() {
20966                        cx.emit(EditorEvent::TitleChanged);
20967                    }
20968
20969                    let buffer_id = edited_buffer.read(cx).remote_id();
20970                    if let Some(project) = self.project.clone() {
20971                        self.register_buffer(buffer_id, cx);
20972                        self.update_lsp_data(Some(buffer_id), window, cx);
20973                        #[allow(clippy::mutable_key_type)]
20974                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20975                            multibuffer
20976                                .all_buffers()
20977                                .into_iter()
20978                                .filter_map(|buffer| {
20979                                    buffer.update(cx, |buffer, cx| {
20980                                        let language = buffer.language()?;
20981                                        let should_discard = project.update(cx, |project, cx| {
20982                                            project.is_local()
20983                                                && !project.has_language_servers_for(buffer, cx)
20984                                        });
20985                                        should_discard.not().then_some(language.clone())
20986                                    })
20987                                })
20988                                .collect::<HashSet<_>>()
20989                        });
20990                        if !languages_affected.is_empty() {
20991                            self.refresh_inlay_hints(
20992                                InlayHintRefreshReason::BufferEdited(languages_affected),
20993                                cx,
20994                            );
20995                        }
20996                    }
20997                }
20998
20999                cx.emit(EditorEvent::BufferEdited);
21000                cx.emit(SearchEvent::MatchesInvalidated);
21001
21002                let Some(project) = &self.project else { return };
21003                let (telemetry, is_via_ssh) = {
21004                    let project = project.read(cx);
21005                    let telemetry = project.client().telemetry().clone();
21006                    let is_via_ssh = project.is_via_remote_server();
21007                    (telemetry, is_via_ssh)
21008                };
21009                telemetry.log_edit_event("editor", is_via_ssh);
21010            }
21011            multi_buffer::Event::ExcerptsAdded {
21012                buffer,
21013                predecessor,
21014                excerpts,
21015            } => {
21016                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21017                let buffer_id = buffer.read(cx).remote_id();
21018                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21019                    && let Some(project) = &self.project
21020                {
21021                    update_uncommitted_diff_for_buffer(
21022                        cx.entity(),
21023                        project,
21024                        [buffer.clone()],
21025                        self.buffer.clone(),
21026                        cx,
21027                    )
21028                    .detach();
21029                }
21030                self.update_lsp_data(Some(buffer_id), window, cx);
21031                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21032                cx.emit(EditorEvent::ExcerptsAdded {
21033                    buffer: buffer.clone(),
21034                    predecessor: *predecessor,
21035                    excerpts: excerpts.clone(),
21036                });
21037            }
21038            multi_buffer::Event::ExcerptsRemoved {
21039                ids,
21040                removed_buffer_ids,
21041            } => {
21042                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21043                for buffer_id in removed_buffer_ids {
21044                    self.registered_buffers.remove(buffer_id);
21045                }
21046                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21047                cx.emit(EditorEvent::ExcerptsRemoved {
21048                    ids: ids.clone(),
21049                    removed_buffer_ids: removed_buffer_ids.clone(),
21050                });
21051            }
21052            multi_buffer::Event::ExcerptsEdited {
21053                excerpt_ids,
21054                buffer_ids,
21055            } => {
21056                self.display_map.update(cx, |map, cx| {
21057                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21058                });
21059                cx.emit(EditorEvent::ExcerptsEdited {
21060                    ids: excerpt_ids.clone(),
21061                });
21062            }
21063            multi_buffer::Event::ExcerptsExpanded { ids } => {
21064                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21065                self.refresh_document_highlights(cx);
21066                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21067            }
21068            multi_buffer::Event::Reparsed(buffer_id) => {
21069                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21070                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21071
21072                cx.emit(EditorEvent::Reparsed(*buffer_id));
21073            }
21074            multi_buffer::Event::DiffHunksToggled => {
21075                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21076            }
21077            multi_buffer::Event::LanguageChanged(buffer_id) => {
21078                self.registered_buffers.remove(&buffer_id);
21079                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21080                cx.emit(EditorEvent::Reparsed(*buffer_id));
21081                cx.notify();
21082            }
21083            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21084            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21085            multi_buffer::Event::FileHandleChanged
21086            | multi_buffer::Event::Reloaded
21087            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21088            multi_buffer::Event::DiagnosticsUpdated => {
21089                self.update_diagnostics_state(window, cx);
21090            }
21091            _ => {}
21092        };
21093    }
21094
21095    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21096        if !self.diagnostics_enabled() {
21097            return;
21098        }
21099        self.refresh_active_diagnostics(cx);
21100        self.refresh_inline_diagnostics(true, window, cx);
21101        self.scrollbar_marker_state.dirty = true;
21102        cx.notify();
21103    }
21104
21105    pub fn start_temporary_diff_override(&mut self) {
21106        self.load_diff_task.take();
21107        self.temporary_diff_override = true;
21108    }
21109
21110    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21111        self.temporary_diff_override = false;
21112        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21113        self.buffer.update(cx, |buffer, cx| {
21114            buffer.set_all_diff_hunks_collapsed(cx);
21115        });
21116
21117        if let Some(project) = self.project.clone() {
21118            self.load_diff_task = Some(
21119                update_uncommitted_diff_for_buffer(
21120                    cx.entity(),
21121                    &project,
21122                    self.buffer.read(cx).all_buffers(),
21123                    self.buffer.clone(),
21124                    cx,
21125                )
21126                .shared(),
21127            );
21128        }
21129    }
21130
21131    fn on_display_map_changed(
21132        &mut self,
21133        _: Entity<DisplayMap>,
21134        _: &mut Window,
21135        cx: &mut Context<Self>,
21136    ) {
21137        cx.notify();
21138    }
21139
21140    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21141        if self.diagnostics_enabled() {
21142            let new_severity = EditorSettings::get_global(cx)
21143                .diagnostics_max_severity
21144                .unwrap_or(DiagnosticSeverity::Hint);
21145            self.set_max_diagnostics_severity(new_severity, cx);
21146        }
21147        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21148        self.update_edit_prediction_settings(cx);
21149        self.refresh_edit_prediction(true, false, window, cx);
21150        self.refresh_inline_values(cx);
21151        self.refresh_inlay_hints(
21152            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21153                self.selections.newest_anchor().head(),
21154                &self.buffer.read(cx).snapshot(cx),
21155                cx,
21156            )),
21157            cx,
21158        );
21159
21160        let old_cursor_shape = self.cursor_shape;
21161        let old_show_breadcrumbs = self.show_breadcrumbs;
21162
21163        {
21164            let editor_settings = EditorSettings::get_global(cx);
21165            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21166            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21167            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21168            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21169        }
21170
21171        if old_cursor_shape != self.cursor_shape {
21172            cx.emit(EditorEvent::CursorShapeChanged);
21173        }
21174
21175        if old_show_breadcrumbs != self.show_breadcrumbs {
21176            cx.emit(EditorEvent::BreadcrumbsChanged);
21177        }
21178
21179        let project_settings = ProjectSettings::get_global(cx);
21180        self.serialize_dirty_buffers =
21181            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21182
21183        if self.mode.is_full() {
21184            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21185            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21186            if self.show_inline_diagnostics != show_inline_diagnostics {
21187                self.show_inline_diagnostics = show_inline_diagnostics;
21188                self.refresh_inline_diagnostics(false, window, cx);
21189            }
21190
21191            if self.git_blame_inline_enabled != inline_blame_enabled {
21192                self.toggle_git_blame_inline_internal(false, window, cx);
21193            }
21194
21195            let minimap_settings = EditorSettings::get_global(cx).minimap;
21196            if self.minimap_visibility != MinimapVisibility::Disabled {
21197                if self.minimap_visibility.settings_visibility()
21198                    != minimap_settings.minimap_enabled()
21199                {
21200                    self.set_minimap_visibility(
21201                        MinimapVisibility::for_mode(self.mode(), cx),
21202                        window,
21203                        cx,
21204                    );
21205                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21206                    minimap_entity.update(cx, |minimap_editor, cx| {
21207                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21208                    })
21209                }
21210            }
21211        }
21212
21213        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21214            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21215        }) {
21216            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21217                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21218            }
21219            self.refresh_colors_for_visible_range(None, window, cx);
21220        }
21221
21222        cx.notify();
21223    }
21224
21225    pub fn set_searchable(&mut self, searchable: bool) {
21226        self.searchable = searchable;
21227    }
21228
21229    pub fn searchable(&self) -> bool {
21230        self.searchable
21231    }
21232
21233    fn open_proposed_changes_editor(
21234        &mut self,
21235        _: &OpenProposedChangesEditor,
21236        window: &mut Window,
21237        cx: &mut Context<Self>,
21238    ) {
21239        let Some(workspace) = self.workspace() else {
21240            cx.propagate();
21241            return;
21242        };
21243
21244        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21245        let multi_buffer = self.buffer.read(cx);
21246        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21247        let mut new_selections_by_buffer = HashMap::default();
21248        for selection in selections {
21249            for (buffer, range, _) in
21250                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21251            {
21252                let mut range = range.to_point(buffer);
21253                range.start.column = 0;
21254                range.end.column = buffer.line_len(range.end.row);
21255                new_selections_by_buffer
21256                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21257                    .or_insert(Vec::new())
21258                    .push(range)
21259            }
21260        }
21261
21262        let proposed_changes_buffers = new_selections_by_buffer
21263            .into_iter()
21264            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21265            .collect::<Vec<_>>();
21266        let proposed_changes_editor = cx.new(|cx| {
21267            ProposedChangesEditor::new(
21268                "Proposed changes",
21269                proposed_changes_buffers,
21270                self.project.clone(),
21271                window,
21272                cx,
21273            )
21274        });
21275
21276        window.defer(cx, move |window, cx| {
21277            workspace.update(cx, |workspace, cx| {
21278                workspace.active_pane().update(cx, |pane, cx| {
21279                    pane.add_item(
21280                        Box::new(proposed_changes_editor),
21281                        true,
21282                        true,
21283                        None,
21284                        window,
21285                        cx,
21286                    );
21287                });
21288            });
21289        });
21290    }
21291
21292    pub fn open_excerpts_in_split(
21293        &mut self,
21294        _: &OpenExcerptsSplit,
21295        window: &mut Window,
21296        cx: &mut Context<Self>,
21297    ) {
21298        self.open_excerpts_common(None, true, window, cx)
21299    }
21300
21301    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21302        self.open_excerpts_common(None, false, window, cx)
21303    }
21304
21305    fn open_excerpts_common(
21306        &mut self,
21307        jump_data: Option<JumpData>,
21308        split: bool,
21309        window: &mut Window,
21310        cx: &mut Context<Self>,
21311    ) {
21312        let Some(workspace) = self.workspace() else {
21313            cx.propagate();
21314            return;
21315        };
21316
21317        if self.buffer.read(cx).is_singleton() {
21318            cx.propagate();
21319            return;
21320        }
21321
21322        let mut new_selections_by_buffer = HashMap::default();
21323        match &jump_data {
21324            Some(JumpData::MultiBufferPoint {
21325                excerpt_id,
21326                position,
21327                anchor,
21328                line_offset_from_top,
21329            }) => {
21330                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21331                if let Some(buffer) = multi_buffer_snapshot
21332                    .buffer_id_for_excerpt(*excerpt_id)
21333                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21334                {
21335                    let buffer_snapshot = buffer.read(cx).snapshot();
21336                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21337                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21338                    } else {
21339                        buffer_snapshot.clip_point(*position, Bias::Left)
21340                    };
21341                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21342                    new_selections_by_buffer.insert(
21343                        buffer,
21344                        (
21345                            vec![jump_to_offset..jump_to_offset],
21346                            Some(*line_offset_from_top),
21347                        ),
21348                    );
21349                }
21350            }
21351            Some(JumpData::MultiBufferRow {
21352                row,
21353                line_offset_from_top,
21354            }) => {
21355                let point = MultiBufferPoint::new(row.0, 0);
21356                if let Some((buffer, buffer_point, _)) =
21357                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21358                {
21359                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21360                    new_selections_by_buffer
21361                        .entry(buffer)
21362                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21363                        .0
21364                        .push(buffer_offset..buffer_offset)
21365                }
21366            }
21367            None => {
21368                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21369                let multi_buffer = self.buffer.read(cx);
21370                for selection in selections {
21371                    for (snapshot, range, _, anchor) in multi_buffer
21372                        .snapshot(cx)
21373                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21374                    {
21375                        if let Some(anchor) = anchor {
21376                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21377                            else {
21378                                continue;
21379                            };
21380                            let offset = text::ToOffset::to_offset(
21381                                &anchor.text_anchor,
21382                                &buffer_handle.read(cx).snapshot(),
21383                            );
21384                            let range = offset..offset;
21385                            new_selections_by_buffer
21386                                .entry(buffer_handle)
21387                                .or_insert((Vec::new(), None))
21388                                .0
21389                                .push(range)
21390                        } else {
21391                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21392                            else {
21393                                continue;
21394                            };
21395                            new_selections_by_buffer
21396                                .entry(buffer_handle)
21397                                .or_insert((Vec::new(), None))
21398                                .0
21399                                .push(range)
21400                        }
21401                    }
21402                }
21403            }
21404        }
21405
21406        new_selections_by_buffer
21407            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21408
21409        if new_selections_by_buffer.is_empty() {
21410            return;
21411        }
21412
21413        // We defer the pane interaction because we ourselves are a workspace item
21414        // and activating a new item causes the pane to call a method on us reentrantly,
21415        // which panics if we're on the stack.
21416        window.defer(cx, move |window, cx| {
21417            workspace.update(cx, |workspace, cx| {
21418                let pane = if split {
21419                    workspace.adjacent_pane(window, cx)
21420                } else {
21421                    workspace.active_pane().clone()
21422                };
21423
21424                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21425                    let editor = buffer
21426                        .read(cx)
21427                        .file()
21428                        .is_none()
21429                        .then(|| {
21430                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21431                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21432                            // Instead, we try to activate the existing editor in the pane first.
21433                            let (editor, pane_item_index) =
21434                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21435                                    let editor = item.downcast::<Editor>()?;
21436                                    let singleton_buffer =
21437                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21438                                    if singleton_buffer == buffer {
21439                                        Some((editor, i))
21440                                    } else {
21441                                        None
21442                                    }
21443                                })?;
21444                            pane.update(cx, |pane, cx| {
21445                                pane.activate_item(pane_item_index, true, true, window, cx)
21446                            });
21447                            Some(editor)
21448                        })
21449                        .flatten()
21450                        .unwrap_or_else(|| {
21451                            workspace.open_project_item::<Self>(
21452                                pane.clone(),
21453                                buffer,
21454                                true,
21455                                true,
21456                                window,
21457                                cx,
21458                            )
21459                        });
21460
21461                    editor.update(cx, |editor, cx| {
21462                        let autoscroll = match scroll_offset {
21463                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21464                            None => Autoscroll::newest(),
21465                        };
21466                        let nav_history = editor.nav_history.take();
21467                        editor.change_selections(
21468                            SelectionEffects::scroll(autoscroll),
21469                            window,
21470                            cx,
21471                            |s| {
21472                                s.select_ranges(ranges);
21473                            },
21474                        );
21475                        editor.nav_history = nav_history;
21476                    });
21477                }
21478            })
21479        });
21480    }
21481
21482    // For now, don't allow opening excerpts in buffers that aren't backed by
21483    // regular project files.
21484    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21485        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21486    }
21487
21488    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21489        let snapshot = self.buffer.read(cx).read(cx);
21490        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21491        Some(
21492            ranges
21493                .iter()
21494                .map(move |range| {
21495                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21496                })
21497                .collect(),
21498        )
21499    }
21500
21501    fn selection_replacement_ranges(
21502        &self,
21503        range: Range<OffsetUtf16>,
21504        cx: &mut App,
21505    ) -> Vec<Range<OffsetUtf16>> {
21506        let selections = self
21507            .selections
21508            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21509        let newest_selection = selections
21510            .iter()
21511            .max_by_key(|selection| selection.id)
21512            .unwrap();
21513        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21514        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21515        let snapshot = self.buffer.read(cx).read(cx);
21516        selections
21517            .into_iter()
21518            .map(|mut selection| {
21519                selection.start.0 =
21520                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21521                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21522                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21523                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21524            })
21525            .collect()
21526    }
21527
21528    fn report_editor_event(
21529        &self,
21530        reported_event: ReportEditorEvent,
21531        file_extension: Option<String>,
21532        cx: &App,
21533    ) {
21534        if cfg!(any(test, feature = "test-support")) {
21535            return;
21536        }
21537
21538        let Some(project) = &self.project else { return };
21539
21540        // If None, we are in a file without an extension
21541        let file = self
21542            .buffer
21543            .read(cx)
21544            .as_singleton()
21545            .and_then(|b| b.read(cx).file());
21546        let file_extension = file_extension.or(file
21547            .as_ref()
21548            .and_then(|file| Path::new(file.file_name(cx)).extension())
21549            .and_then(|e| e.to_str())
21550            .map(|a| a.to_string()));
21551
21552        let vim_mode = vim_enabled(cx);
21553
21554        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21555        let copilot_enabled = edit_predictions_provider
21556            == language::language_settings::EditPredictionProvider::Copilot;
21557        let copilot_enabled_for_language = self
21558            .buffer
21559            .read(cx)
21560            .language_settings(cx)
21561            .show_edit_predictions;
21562
21563        let project = project.read(cx);
21564        let event_type = reported_event.event_type();
21565
21566        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21567            telemetry::event!(
21568                event_type,
21569                type = if auto_saved {"autosave"} else {"manual"},
21570                file_extension,
21571                vim_mode,
21572                copilot_enabled,
21573                copilot_enabled_for_language,
21574                edit_predictions_provider,
21575                is_via_ssh = project.is_via_remote_server(),
21576            );
21577        } else {
21578            telemetry::event!(
21579                event_type,
21580                file_extension,
21581                vim_mode,
21582                copilot_enabled,
21583                copilot_enabled_for_language,
21584                edit_predictions_provider,
21585                is_via_ssh = project.is_via_remote_server(),
21586            );
21587        };
21588    }
21589
21590    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21591    /// with each line being an array of {text, highlight} objects.
21592    fn copy_highlight_json(
21593        &mut self,
21594        _: &CopyHighlightJson,
21595        window: &mut Window,
21596        cx: &mut Context<Self>,
21597    ) {
21598        #[derive(Serialize)]
21599        struct Chunk<'a> {
21600            text: String,
21601            highlight: Option<&'a str>,
21602        }
21603
21604        let snapshot = self.buffer.read(cx).snapshot(cx);
21605        let range = self
21606            .selected_text_range(false, window, cx)
21607            .and_then(|selection| {
21608                if selection.range.is_empty() {
21609                    None
21610                } else {
21611                    Some(selection.range)
21612                }
21613            })
21614            .unwrap_or_else(|| 0..snapshot.len());
21615
21616        let chunks = snapshot.chunks(range, true);
21617        let mut lines = Vec::new();
21618        let mut line: VecDeque<Chunk> = VecDeque::new();
21619
21620        let Some(style) = self.style.as_ref() else {
21621            return;
21622        };
21623
21624        for chunk in chunks {
21625            let highlight = chunk
21626                .syntax_highlight_id
21627                .and_then(|id| id.name(&style.syntax));
21628            let mut chunk_lines = chunk.text.split('\n').peekable();
21629            while let Some(text) = chunk_lines.next() {
21630                let mut merged_with_last_token = false;
21631                if let Some(last_token) = line.back_mut()
21632                    && last_token.highlight == highlight
21633                {
21634                    last_token.text.push_str(text);
21635                    merged_with_last_token = true;
21636                }
21637
21638                if !merged_with_last_token {
21639                    line.push_back(Chunk {
21640                        text: text.into(),
21641                        highlight,
21642                    });
21643                }
21644
21645                if chunk_lines.peek().is_some() {
21646                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21647                        line.pop_front();
21648                    }
21649                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21650                        line.pop_back();
21651                    }
21652
21653                    lines.push(mem::take(&mut line));
21654                }
21655            }
21656        }
21657
21658        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21659            return;
21660        };
21661        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21662    }
21663
21664    pub fn open_context_menu(
21665        &mut self,
21666        _: &OpenContextMenu,
21667        window: &mut Window,
21668        cx: &mut Context<Self>,
21669    ) {
21670        self.request_autoscroll(Autoscroll::newest(), cx);
21671        let position = self
21672            .selections
21673            .newest_display(&self.display_snapshot(cx))
21674            .start;
21675        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21676    }
21677
21678    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21679        &self.inlay_hint_cache
21680    }
21681
21682    pub fn replay_insert_event(
21683        &mut self,
21684        text: &str,
21685        relative_utf16_range: Option<Range<isize>>,
21686        window: &mut Window,
21687        cx: &mut Context<Self>,
21688    ) {
21689        if !self.input_enabled {
21690            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21691            return;
21692        }
21693        if let Some(relative_utf16_range) = relative_utf16_range {
21694            let selections = self
21695                .selections
21696                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21697            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21698                let new_ranges = selections.into_iter().map(|range| {
21699                    let start = OffsetUtf16(
21700                        range
21701                            .head()
21702                            .0
21703                            .saturating_add_signed(relative_utf16_range.start),
21704                    );
21705                    let end = OffsetUtf16(
21706                        range
21707                            .head()
21708                            .0
21709                            .saturating_add_signed(relative_utf16_range.end),
21710                    );
21711                    start..end
21712                });
21713                s.select_ranges(new_ranges);
21714            });
21715        }
21716
21717        self.handle_input(text, window, cx);
21718    }
21719
21720    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21721        let Some(provider) = self.semantics_provider.as_ref() else {
21722            return false;
21723        };
21724
21725        let mut supports = false;
21726        self.buffer().update(cx, |this, cx| {
21727            this.for_each_buffer(|buffer| {
21728                supports |= provider.supports_inlay_hints(buffer, cx);
21729            });
21730        });
21731
21732        supports
21733    }
21734
21735    pub fn is_focused(&self, window: &Window) -> bool {
21736        self.focus_handle.is_focused(window)
21737    }
21738
21739    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21740        cx.emit(EditorEvent::Focused);
21741
21742        if let Some(descendant) = self
21743            .last_focused_descendant
21744            .take()
21745            .and_then(|descendant| descendant.upgrade())
21746        {
21747            window.focus(&descendant);
21748        } else {
21749            if let Some(blame) = self.blame.as_ref() {
21750                blame.update(cx, GitBlame::focus)
21751            }
21752
21753            self.blink_manager.update(cx, BlinkManager::enable);
21754            self.show_cursor_names(window, cx);
21755            self.buffer.update(cx, |buffer, cx| {
21756                buffer.finalize_last_transaction(cx);
21757                if self.leader_id.is_none() {
21758                    buffer.set_active_selections(
21759                        &self.selections.disjoint_anchors_arc(),
21760                        self.selections.line_mode(),
21761                        self.cursor_shape,
21762                        cx,
21763                    );
21764                }
21765            });
21766        }
21767    }
21768
21769    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21770        cx.emit(EditorEvent::FocusedIn)
21771    }
21772
21773    fn handle_focus_out(
21774        &mut self,
21775        event: FocusOutEvent,
21776        _window: &mut Window,
21777        cx: &mut Context<Self>,
21778    ) {
21779        if event.blurred != self.focus_handle {
21780            self.last_focused_descendant = Some(event.blurred);
21781        }
21782        self.selection_drag_state = SelectionDragState::None;
21783        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21784    }
21785
21786    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21787        self.blink_manager.update(cx, BlinkManager::disable);
21788        self.buffer
21789            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21790
21791        if let Some(blame) = self.blame.as_ref() {
21792            blame.update(cx, GitBlame::blur)
21793        }
21794        if !self.hover_state.focused(window, cx) {
21795            hide_hover(self, cx);
21796        }
21797        if !self
21798            .context_menu
21799            .borrow()
21800            .as_ref()
21801            .is_some_and(|context_menu| context_menu.focused(window, cx))
21802        {
21803            self.hide_context_menu(window, cx);
21804        }
21805        self.take_active_edit_prediction(cx);
21806        cx.emit(EditorEvent::Blurred);
21807        cx.notify();
21808    }
21809
21810    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21811        let mut pending: String = window
21812            .pending_input_keystrokes()
21813            .into_iter()
21814            .flatten()
21815            .filter_map(|keystroke| {
21816                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21817                    keystroke.key_char.clone()
21818                } else {
21819                    None
21820                }
21821            })
21822            .collect();
21823
21824        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21825            pending = "".to_string();
21826        }
21827
21828        let existing_pending = self
21829            .text_highlights::<PendingInput>(cx)
21830            .map(|(_, ranges)| ranges.to_vec());
21831        if existing_pending.is_none() && pending.is_empty() {
21832            return;
21833        }
21834        let transaction =
21835            self.transact(window, cx, |this, window, cx| {
21836                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21837                let edits = selections
21838                    .iter()
21839                    .map(|selection| (selection.end..selection.end, pending.clone()));
21840                this.edit(edits, cx);
21841                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21842                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21843                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21844                    }));
21845                });
21846                if let Some(existing_ranges) = existing_pending {
21847                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21848                    this.edit(edits, cx);
21849                }
21850            });
21851
21852        let snapshot = self.snapshot(window, cx);
21853        let ranges = self
21854            .selections
21855            .all::<usize>(&snapshot.display_snapshot)
21856            .into_iter()
21857            .map(|selection| {
21858                snapshot.buffer_snapshot().anchor_after(selection.end)
21859                    ..snapshot
21860                        .buffer_snapshot()
21861                        .anchor_before(selection.end + pending.len())
21862            })
21863            .collect();
21864
21865        if pending.is_empty() {
21866            self.clear_highlights::<PendingInput>(cx);
21867        } else {
21868            self.highlight_text::<PendingInput>(
21869                ranges,
21870                HighlightStyle {
21871                    underline: Some(UnderlineStyle {
21872                        thickness: px(1.),
21873                        color: None,
21874                        wavy: false,
21875                    }),
21876                    ..Default::default()
21877                },
21878                cx,
21879            );
21880        }
21881
21882        self.ime_transaction = self.ime_transaction.or(transaction);
21883        if let Some(transaction) = self.ime_transaction {
21884            self.buffer.update(cx, |buffer, cx| {
21885                buffer.group_until_transaction(transaction, cx);
21886            });
21887        }
21888
21889        if self.text_highlights::<PendingInput>(cx).is_none() {
21890            self.ime_transaction.take();
21891        }
21892    }
21893
21894    pub fn register_action_renderer(
21895        &mut self,
21896        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21897    ) -> Subscription {
21898        let id = self.next_editor_action_id.post_inc();
21899        self.editor_actions
21900            .borrow_mut()
21901            .insert(id, Box::new(listener));
21902
21903        let editor_actions = self.editor_actions.clone();
21904        Subscription::new(move || {
21905            editor_actions.borrow_mut().remove(&id);
21906        })
21907    }
21908
21909    pub fn register_action<A: Action>(
21910        &mut self,
21911        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21912    ) -> Subscription {
21913        let id = self.next_editor_action_id.post_inc();
21914        let listener = Arc::new(listener);
21915        self.editor_actions.borrow_mut().insert(
21916            id,
21917            Box::new(move |_, window, _| {
21918                let listener = listener.clone();
21919                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21920                    let action = action.downcast_ref().unwrap();
21921                    if phase == DispatchPhase::Bubble {
21922                        listener(action, window, cx)
21923                    }
21924                })
21925            }),
21926        );
21927
21928        let editor_actions = self.editor_actions.clone();
21929        Subscription::new(move || {
21930            editor_actions.borrow_mut().remove(&id);
21931        })
21932    }
21933
21934    pub fn file_header_size(&self) -> u32 {
21935        FILE_HEADER_HEIGHT
21936    }
21937
21938    pub fn restore(
21939        &mut self,
21940        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21941        window: &mut Window,
21942        cx: &mut Context<Self>,
21943    ) {
21944        let workspace = self.workspace();
21945        let project = self.project();
21946        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21947            let mut tasks = Vec::new();
21948            for (buffer_id, changes) in revert_changes {
21949                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21950                    buffer.update(cx, |buffer, cx| {
21951                        buffer.edit(
21952                            changes
21953                                .into_iter()
21954                                .map(|(range, text)| (range, text.to_string())),
21955                            None,
21956                            cx,
21957                        );
21958                    });
21959
21960                    if let Some(project) =
21961                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21962                    {
21963                        project.update(cx, |project, cx| {
21964                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21965                        })
21966                    }
21967                }
21968            }
21969            tasks
21970        });
21971        cx.spawn_in(window, async move |_, cx| {
21972            for (buffer, task) in save_tasks {
21973                let result = task.await;
21974                if result.is_err() {
21975                    let Some(path) = buffer
21976                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21977                        .ok()
21978                    else {
21979                        continue;
21980                    };
21981                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21982                        let Some(task) = cx
21983                            .update_window_entity(workspace, |workspace, window, cx| {
21984                                workspace
21985                                    .open_path_preview(path, None, false, false, false, window, cx)
21986                            })
21987                            .ok()
21988                        else {
21989                            continue;
21990                        };
21991                        task.await.log_err();
21992                    }
21993                }
21994            }
21995        })
21996        .detach();
21997        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21998            selections.refresh()
21999        });
22000    }
22001
22002    pub fn to_pixel_point(
22003        &self,
22004        source: multi_buffer::Anchor,
22005        editor_snapshot: &EditorSnapshot,
22006        window: &mut Window,
22007    ) -> Option<gpui::Point<Pixels>> {
22008        let source_point = source.to_display_point(editor_snapshot);
22009        self.display_to_pixel_point(source_point, editor_snapshot, window)
22010    }
22011
22012    pub fn display_to_pixel_point(
22013        &self,
22014        source: DisplayPoint,
22015        editor_snapshot: &EditorSnapshot,
22016        window: &mut Window,
22017    ) -> Option<gpui::Point<Pixels>> {
22018        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22019        let text_layout_details = self.text_layout_details(window);
22020        let scroll_top = text_layout_details
22021            .scroll_anchor
22022            .scroll_position(editor_snapshot)
22023            .y;
22024
22025        if source.row().as_f64() < scroll_top.floor() {
22026            return None;
22027        }
22028        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22029        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22030        Some(gpui::Point::new(source_x, source_y))
22031    }
22032
22033    pub fn has_visible_completions_menu(&self) -> bool {
22034        !self.edit_prediction_preview_is_active()
22035            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22036                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22037            })
22038    }
22039
22040    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22041        if self.mode.is_minimap() {
22042            return;
22043        }
22044        self.addons
22045            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22046    }
22047
22048    pub fn unregister_addon<T: Addon>(&mut self) {
22049        self.addons.remove(&std::any::TypeId::of::<T>());
22050    }
22051
22052    pub fn addon<T: Addon>(&self) -> Option<&T> {
22053        let type_id = std::any::TypeId::of::<T>();
22054        self.addons
22055            .get(&type_id)
22056            .and_then(|item| item.to_any().downcast_ref::<T>())
22057    }
22058
22059    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22060        let type_id = std::any::TypeId::of::<T>();
22061        self.addons
22062            .get_mut(&type_id)
22063            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22064    }
22065
22066    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22067        let text_layout_details = self.text_layout_details(window);
22068        let style = &text_layout_details.editor_style;
22069        let font_id = window.text_system().resolve_font(&style.text.font());
22070        let font_size = style.text.font_size.to_pixels(window.rem_size());
22071        let line_height = style.text.line_height_in_pixels(window.rem_size());
22072        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22073        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22074
22075        CharacterDimensions {
22076            em_width,
22077            em_advance,
22078            line_height,
22079        }
22080    }
22081
22082    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22083        self.load_diff_task.clone()
22084    }
22085
22086    fn read_metadata_from_db(
22087        &mut self,
22088        item_id: u64,
22089        workspace_id: WorkspaceId,
22090        window: &mut Window,
22091        cx: &mut Context<Editor>,
22092    ) {
22093        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22094            && !self.mode.is_minimap()
22095            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22096        {
22097            let buffer_snapshot = OnceCell::new();
22098
22099            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22100                && !folds.is_empty()
22101            {
22102                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22103                self.fold_ranges(
22104                    folds
22105                        .into_iter()
22106                        .map(|(start, end)| {
22107                            snapshot.clip_offset(start, Bias::Left)
22108                                ..snapshot.clip_offset(end, Bias::Right)
22109                        })
22110                        .collect(),
22111                    false,
22112                    window,
22113                    cx,
22114                );
22115            }
22116
22117            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22118                && !selections.is_empty()
22119            {
22120                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22121                // skip adding the initial selection to selection history
22122                self.selection_history.mode = SelectionHistoryMode::Skipping;
22123                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22124                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22125                        snapshot.clip_offset(start, Bias::Left)
22126                            ..snapshot.clip_offset(end, Bias::Right)
22127                    }));
22128                });
22129                self.selection_history.mode = SelectionHistoryMode::Normal;
22130            };
22131        }
22132
22133        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22134    }
22135
22136    fn update_lsp_data(
22137        &mut self,
22138        for_buffer: Option<BufferId>,
22139        window: &mut Window,
22140        cx: &mut Context<'_, Self>,
22141    ) {
22142        self.pull_diagnostics(for_buffer, window, cx);
22143        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22144    }
22145
22146    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22147        if self.ignore_lsp_data() {
22148            return;
22149        }
22150        for (_, (visible_buffer, _, _)) in self.visible_excerpts(None, cx) {
22151            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22152        }
22153    }
22154
22155    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) -> bool {
22156        if !self.registered_buffers.contains_key(&buffer_id)
22157            && let Some(project) = self.project.as_ref()
22158        {
22159            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22160                project.update(cx, |project, cx| {
22161                    self.registered_buffers.insert(
22162                        buffer_id,
22163                        project.register_buffer_with_language_servers(&buffer, cx),
22164                    );
22165                });
22166                return true;
22167            } else {
22168                self.registered_buffers.remove(&buffer_id);
22169            }
22170        }
22171
22172        false
22173    }
22174
22175    fn ignore_lsp_data(&self) -> bool {
22176        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22177        // skip any LSP updates for it.
22178        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22179    }
22180}
22181
22182fn edit_for_markdown_paste<'a>(
22183    buffer: &MultiBufferSnapshot,
22184    range: Range<usize>,
22185    to_insert: &'a str,
22186    url: Option<url::Url>,
22187) -> (Range<usize>, Cow<'a, str>) {
22188    if url.is_none() {
22189        return (range, Cow::Borrowed(to_insert));
22190    };
22191
22192    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22193
22194    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22195        Cow::Borrowed(to_insert)
22196    } else {
22197        Cow::Owned(format!("[{old_text}]({to_insert})"))
22198    };
22199    (range, new_text)
22200}
22201
22202fn vim_enabled(cx: &App) -> bool {
22203    vim_mode_setting::VimModeSetting::try_get(cx)
22204        .map(|vim_mode| vim_mode.0)
22205        .unwrap_or(false)
22206}
22207
22208fn process_completion_for_edit(
22209    completion: &Completion,
22210    intent: CompletionIntent,
22211    buffer: &Entity<Buffer>,
22212    cursor_position: &text::Anchor,
22213    cx: &mut Context<Editor>,
22214) -> CompletionEdit {
22215    let buffer = buffer.read(cx);
22216    let buffer_snapshot = buffer.snapshot();
22217    let (snippet, new_text) = if completion.is_snippet() {
22218        let mut snippet_source = completion.new_text.clone();
22219        // Workaround for typescript language server issues so that methods don't expand within
22220        // strings and functions with type expressions. The previous point is used because the query
22221        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22222        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22223        let previous_point = if previous_point.column > 0 {
22224            cursor_position.to_previous_offset(&buffer_snapshot)
22225        } else {
22226            cursor_position.to_offset(&buffer_snapshot)
22227        };
22228        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22229            && scope.prefers_label_for_snippet_in_completion()
22230            && let Some(label) = completion.label()
22231            && matches!(
22232                completion.kind(),
22233                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22234            )
22235        {
22236            snippet_source = label;
22237        }
22238        match Snippet::parse(&snippet_source).log_err() {
22239            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22240            None => (None, completion.new_text.clone()),
22241        }
22242    } else {
22243        (None, completion.new_text.clone())
22244    };
22245
22246    let mut range_to_replace = {
22247        let replace_range = &completion.replace_range;
22248        if let CompletionSource::Lsp {
22249            insert_range: Some(insert_range),
22250            ..
22251        } = &completion.source
22252        {
22253            debug_assert_eq!(
22254                insert_range.start, replace_range.start,
22255                "insert_range and replace_range should start at the same position"
22256            );
22257            debug_assert!(
22258                insert_range
22259                    .start
22260                    .cmp(cursor_position, &buffer_snapshot)
22261                    .is_le(),
22262                "insert_range should start before or at cursor position"
22263            );
22264            debug_assert!(
22265                replace_range
22266                    .start
22267                    .cmp(cursor_position, &buffer_snapshot)
22268                    .is_le(),
22269                "replace_range should start before or at cursor position"
22270            );
22271
22272            let should_replace = match intent {
22273                CompletionIntent::CompleteWithInsert => false,
22274                CompletionIntent::CompleteWithReplace => true,
22275                CompletionIntent::Complete | CompletionIntent::Compose => {
22276                    let insert_mode =
22277                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22278                            .completions
22279                            .lsp_insert_mode;
22280                    match insert_mode {
22281                        LspInsertMode::Insert => false,
22282                        LspInsertMode::Replace => true,
22283                        LspInsertMode::ReplaceSubsequence => {
22284                            let mut text_to_replace = buffer.chars_for_range(
22285                                buffer.anchor_before(replace_range.start)
22286                                    ..buffer.anchor_after(replace_range.end),
22287                            );
22288                            let mut current_needle = text_to_replace.next();
22289                            for haystack_ch in completion.label.text.chars() {
22290                                if let Some(needle_ch) = current_needle
22291                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22292                                {
22293                                    current_needle = text_to_replace.next();
22294                                }
22295                            }
22296                            current_needle.is_none()
22297                        }
22298                        LspInsertMode::ReplaceSuffix => {
22299                            if replace_range
22300                                .end
22301                                .cmp(cursor_position, &buffer_snapshot)
22302                                .is_gt()
22303                            {
22304                                let range_after_cursor = *cursor_position..replace_range.end;
22305                                let text_after_cursor = buffer
22306                                    .text_for_range(
22307                                        buffer.anchor_before(range_after_cursor.start)
22308                                            ..buffer.anchor_after(range_after_cursor.end),
22309                                    )
22310                                    .collect::<String>()
22311                                    .to_ascii_lowercase();
22312                                completion
22313                                    .label
22314                                    .text
22315                                    .to_ascii_lowercase()
22316                                    .ends_with(&text_after_cursor)
22317                            } else {
22318                                true
22319                            }
22320                        }
22321                    }
22322                }
22323            };
22324
22325            if should_replace {
22326                replace_range.clone()
22327            } else {
22328                insert_range.clone()
22329            }
22330        } else {
22331            replace_range.clone()
22332        }
22333    };
22334
22335    if range_to_replace
22336        .end
22337        .cmp(cursor_position, &buffer_snapshot)
22338        .is_lt()
22339    {
22340        range_to_replace.end = *cursor_position;
22341    }
22342
22343    CompletionEdit {
22344        new_text,
22345        replace_range: range_to_replace.to_offset(buffer),
22346        snippet,
22347    }
22348}
22349
22350struct CompletionEdit {
22351    new_text: String,
22352    replace_range: Range<usize>,
22353    snippet: Option<Snippet>,
22354}
22355
22356fn insert_extra_newline_brackets(
22357    buffer: &MultiBufferSnapshot,
22358    range: Range<usize>,
22359    language: &language::LanguageScope,
22360) -> bool {
22361    let leading_whitespace_len = buffer
22362        .reversed_chars_at(range.start)
22363        .take_while(|c| c.is_whitespace() && *c != '\n')
22364        .map(|c| c.len_utf8())
22365        .sum::<usize>();
22366    let trailing_whitespace_len = buffer
22367        .chars_at(range.end)
22368        .take_while(|c| c.is_whitespace() && *c != '\n')
22369        .map(|c| c.len_utf8())
22370        .sum::<usize>();
22371    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22372
22373    language.brackets().any(|(pair, enabled)| {
22374        let pair_start = pair.start.trim_end();
22375        let pair_end = pair.end.trim_start();
22376
22377        enabled
22378            && pair.newline
22379            && buffer.contains_str_at(range.end, pair_end)
22380            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22381    })
22382}
22383
22384fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22385    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22386        [(buffer, range, _)] => (*buffer, range.clone()),
22387        _ => return false,
22388    };
22389    let pair = {
22390        let mut result: Option<BracketMatch> = None;
22391
22392        for pair in buffer
22393            .all_bracket_ranges(range.clone())
22394            .filter(move |pair| {
22395                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22396            })
22397        {
22398            let len = pair.close_range.end - pair.open_range.start;
22399
22400            if let Some(existing) = &result {
22401                let existing_len = existing.close_range.end - existing.open_range.start;
22402                if len > existing_len {
22403                    continue;
22404                }
22405            }
22406
22407            result = Some(pair);
22408        }
22409
22410        result
22411    };
22412    let Some(pair) = pair else {
22413        return false;
22414    };
22415    pair.newline_only
22416        && buffer
22417            .chars_for_range(pair.open_range.end..range.start)
22418            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22419            .all(|c| c.is_whitespace() && c != '\n')
22420}
22421
22422fn update_uncommitted_diff_for_buffer(
22423    editor: Entity<Editor>,
22424    project: &Entity<Project>,
22425    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22426    buffer: Entity<MultiBuffer>,
22427    cx: &mut App,
22428) -> Task<()> {
22429    let mut tasks = Vec::new();
22430    project.update(cx, |project, cx| {
22431        for buffer in buffers {
22432            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22433                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22434            }
22435        }
22436    });
22437    cx.spawn(async move |cx| {
22438        let diffs = future::join_all(tasks).await;
22439        if editor
22440            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22441            .unwrap_or(false)
22442        {
22443            return;
22444        }
22445
22446        buffer
22447            .update(cx, |buffer, cx| {
22448                for diff in diffs.into_iter().flatten() {
22449                    buffer.add_diff(diff, cx);
22450                }
22451            })
22452            .ok();
22453    })
22454}
22455
22456fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22457    let tab_size = tab_size.get() as usize;
22458    let mut width = offset;
22459
22460    for ch in text.chars() {
22461        width += if ch == '\t' {
22462            tab_size - (width % tab_size)
22463        } else {
22464            1
22465        };
22466    }
22467
22468    width - offset
22469}
22470
22471#[cfg(test)]
22472mod tests {
22473    use super::*;
22474
22475    #[test]
22476    fn test_string_size_with_expanded_tabs() {
22477        let nz = |val| NonZeroU32::new(val).unwrap();
22478        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22479        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22480        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22481        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22482        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22483        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22484        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22485        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22486    }
22487}
22488
22489/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22490struct WordBreakingTokenizer<'a> {
22491    input: &'a str,
22492}
22493
22494impl<'a> WordBreakingTokenizer<'a> {
22495    fn new(input: &'a str) -> Self {
22496        Self { input }
22497    }
22498}
22499
22500fn is_char_ideographic(ch: char) -> bool {
22501    use unicode_script::Script::*;
22502    use unicode_script::UnicodeScript;
22503    matches!(ch.script(), Han | Tangut | Yi)
22504}
22505
22506fn is_grapheme_ideographic(text: &str) -> bool {
22507    text.chars().any(is_char_ideographic)
22508}
22509
22510fn is_grapheme_whitespace(text: &str) -> bool {
22511    text.chars().any(|x| x.is_whitespace())
22512}
22513
22514fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22515    text.chars()
22516        .next()
22517        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22518}
22519
22520#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22521enum WordBreakToken<'a> {
22522    Word { token: &'a str, grapheme_len: usize },
22523    InlineWhitespace { token: &'a str, grapheme_len: usize },
22524    Newline,
22525}
22526
22527impl<'a> Iterator for WordBreakingTokenizer<'a> {
22528    /// Yields a span, the count of graphemes in the token, and whether it was
22529    /// whitespace. Note that it also breaks at word boundaries.
22530    type Item = WordBreakToken<'a>;
22531
22532    fn next(&mut self) -> Option<Self::Item> {
22533        use unicode_segmentation::UnicodeSegmentation;
22534        if self.input.is_empty() {
22535            return None;
22536        }
22537
22538        let mut iter = self.input.graphemes(true).peekable();
22539        let mut offset = 0;
22540        let mut grapheme_len = 0;
22541        if let Some(first_grapheme) = iter.next() {
22542            let is_newline = first_grapheme == "\n";
22543            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22544            offset += first_grapheme.len();
22545            grapheme_len += 1;
22546            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22547                if let Some(grapheme) = iter.peek().copied()
22548                    && should_stay_with_preceding_ideograph(grapheme)
22549                {
22550                    offset += grapheme.len();
22551                    grapheme_len += 1;
22552                }
22553            } else {
22554                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22555                let mut next_word_bound = words.peek().copied();
22556                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22557                    next_word_bound = words.next();
22558                }
22559                while let Some(grapheme) = iter.peek().copied() {
22560                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22561                        break;
22562                    };
22563                    if is_grapheme_whitespace(grapheme) != is_whitespace
22564                        || (grapheme == "\n") != is_newline
22565                    {
22566                        break;
22567                    };
22568                    offset += grapheme.len();
22569                    grapheme_len += 1;
22570                    iter.next();
22571                }
22572            }
22573            let token = &self.input[..offset];
22574            self.input = &self.input[offset..];
22575            if token == "\n" {
22576                Some(WordBreakToken::Newline)
22577            } else if is_whitespace {
22578                Some(WordBreakToken::InlineWhitespace {
22579                    token,
22580                    grapheme_len,
22581                })
22582            } else {
22583                Some(WordBreakToken::Word {
22584                    token,
22585                    grapheme_len,
22586                })
22587            }
22588        } else {
22589            None
22590        }
22591    }
22592}
22593
22594#[test]
22595fn test_word_breaking_tokenizer() {
22596    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22597        ("", &[]),
22598        ("  ", &[whitespace("  ", 2)]),
22599        ("Ʒ", &[word("Ʒ", 1)]),
22600        ("Ǽ", &[word("Ǽ", 1)]),
22601        ("", &[word("", 1)]),
22602        ("⋑⋑", &[word("⋑⋑", 2)]),
22603        (
22604            "原理,进而",
22605            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22606        ),
22607        (
22608            "hello world",
22609            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22610        ),
22611        (
22612            "hello, world",
22613            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22614        ),
22615        (
22616            "  hello world",
22617            &[
22618                whitespace("  ", 2),
22619                word("hello", 5),
22620                whitespace(" ", 1),
22621                word("world", 5),
22622            ],
22623        ),
22624        (
22625            "这是什么 \n 钢笔",
22626            &[
22627                word("", 1),
22628                word("", 1),
22629                word("", 1),
22630                word("", 1),
22631                whitespace(" ", 1),
22632                newline(),
22633                whitespace(" ", 1),
22634                word("", 1),
22635                word("", 1),
22636            ],
22637        ),
22638        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22639    ];
22640
22641    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22642        WordBreakToken::Word {
22643            token,
22644            grapheme_len,
22645        }
22646    }
22647
22648    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22649        WordBreakToken::InlineWhitespace {
22650            token,
22651            grapheme_len,
22652        }
22653    }
22654
22655    fn newline() -> WordBreakToken<'static> {
22656        WordBreakToken::Newline
22657    }
22658
22659    for (input, result) in tests {
22660        assert_eq!(
22661            WordBreakingTokenizer::new(input)
22662                .collect::<Vec<_>>()
22663                .as_slice(),
22664            *result,
22665        );
22666    }
22667}
22668
22669fn wrap_with_prefix(
22670    first_line_prefix: String,
22671    subsequent_lines_prefix: String,
22672    unwrapped_text: String,
22673    wrap_column: usize,
22674    tab_size: NonZeroU32,
22675    preserve_existing_whitespace: bool,
22676) -> String {
22677    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22678    let subsequent_lines_prefix_len =
22679        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22680    let mut wrapped_text = String::new();
22681    let mut current_line = first_line_prefix;
22682    let mut is_first_line = true;
22683
22684    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22685    let mut current_line_len = first_line_prefix_len;
22686    let mut in_whitespace = false;
22687    for token in tokenizer {
22688        let have_preceding_whitespace = in_whitespace;
22689        match token {
22690            WordBreakToken::Word {
22691                token,
22692                grapheme_len,
22693            } => {
22694                in_whitespace = false;
22695                let current_prefix_len = if is_first_line {
22696                    first_line_prefix_len
22697                } else {
22698                    subsequent_lines_prefix_len
22699                };
22700                if current_line_len + grapheme_len > wrap_column
22701                    && current_line_len != current_prefix_len
22702                {
22703                    wrapped_text.push_str(current_line.trim_end());
22704                    wrapped_text.push('\n');
22705                    is_first_line = false;
22706                    current_line = subsequent_lines_prefix.clone();
22707                    current_line_len = subsequent_lines_prefix_len;
22708                }
22709                current_line.push_str(token);
22710                current_line_len += grapheme_len;
22711            }
22712            WordBreakToken::InlineWhitespace {
22713                mut token,
22714                mut grapheme_len,
22715            } => {
22716                in_whitespace = true;
22717                if have_preceding_whitespace && !preserve_existing_whitespace {
22718                    continue;
22719                }
22720                if !preserve_existing_whitespace {
22721                    // Keep a single whitespace grapheme as-is
22722                    if let Some(first) =
22723                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22724                    {
22725                        token = first;
22726                    } else {
22727                        token = " ";
22728                    }
22729                    grapheme_len = 1;
22730                }
22731                let current_prefix_len = if is_first_line {
22732                    first_line_prefix_len
22733                } else {
22734                    subsequent_lines_prefix_len
22735                };
22736                if current_line_len + grapheme_len > wrap_column {
22737                    wrapped_text.push_str(current_line.trim_end());
22738                    wrapped_text.push('\n');
22739                    is_first_line = false;
22740                    current_line = subsequent_lines_prefix.clone();
22741                    current_line_len = subsequent_lines_prefix_len;
22742                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22743                    current_line.push_str(token);
22744                    current_line_len += grapheme_len;
22745                }
22746            }
22747            WordBreakToken::Newline => {
22748                in_whitespace = true;
22749                let current_prefix_len = if is_first_line {
22750                    first_line_prefix_len
22751                } else {
22752                    subsequent_lines_prefix_len
22753                };
22754                if preserve_existing_whitespace {
22755                    wrapped_text.push_str(current_line.trim_end());
22756                    wrapped_text.push('\n');
22757                    is_first_line = false;
22758                    current_line = subsequent_lines_prefix.clone();
22759                    current_line_len = subsequent_lines_prefix_len;
22760                } else if have_preceding_whitespace {
22761                    continue;
22762                } else if current_line_len + 1 > wrap_column
22763                    && current_line_len != current_prefix_len
22764                {
22765                    wrapped_text.push_str(current_line.trim_end());
22766                    wrapped_text.push('\n');
22767                    is_first_line = false;
22768                    current_line = subsequent_lines_prefix.clone();
22769                    current_line_len = subsequent_lines_prefix_len;
22770                } else if current_line_len != current_prefix_len {
22771                    current_line.push(' ');
22772                    current_line_len += 1;
22773                }
22774            }
22775        }
22776    }
22777
22778    if !current_line.is_empty() {
22779        wrapped_text.push_str(&current_line);
22780    }
22781    wrapped_text
22782}
22783
22784#[test]
22785fn test_wrap_with_prefix() {
22786    assert_eq!(
22787        wrap_with_prefix(
22788            "# ".to_string(),
22789            "# ".to_string(),
22790            "abcdefg".to_string(),
22791            4,
22792            NonZeroU32::new(4).unwrap(),
22793            false,
22794        ),
22795        "# abcdefg"
22796    );
22797    assert_eq!(
22798        wrap_with_prefix(
22799            "".to_string(),
22800            "".to_string(),
22801            "\thello world".to_string(),
22802            8,
22803            NonZeroU32::new(4).unwrap(),
22804            false,
22805        ),
22806        "hello\nworld"
22807    );
22808    assert_eq!(
22809        wrap_with_prefix(
22810            "// ".to_string(),
22811            "// ".to_string(),
22812            "xx \nyy zz aa bb cc".to_string(),
22813            12,
22814            NonZeroU32::new(4).unwrap(),
22815            false,
22816        ),
22817        "// xx yy zz\n// aa bb cc"
22818    );
22819    assert_eq!(
22820        wrap_with_prefix(
22821            String::new(),
22822            String::new(),
22823            "这是什么 \n 钢笔".to_string(),
22824            3,
22825            NonZeroU32::new(4).unwrap(),
22826            false,
22827        ),
22828        "这是什\n么 钢\n"
22829    );
22830    assert_eq!(
22831        wrap_with_prefix(
22832            String::new(),
22833            String::new(),
22834            format!("foo{}bar", '\u{2009}'), // thin space
22835            80,
22836            NonZeroU32::new(4).unwrap(),
22837            false,
22838        ),
22839        format!("foo{}bar", '\u{2009}')
22840    );
22841}
22842
22843pub trait CollaborationHub {
22844    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22845    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22846    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22847}
22848
22849impl CollaborationHub for Entity<Project> {
22850    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22851        self.read(cx).collaborators()
22852    }
22853
22854    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22855        self.read(cx).user_store().read(cx).participant_indices()
22856    }
22857
22858    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22859        let this = self.read(cx);
22860        let user_ids = this.collaborators().values().map(|c| c.user_id);
22861        this.user_store().read(cx).participant_names(user_ids, cx)
22862    }
22863}
22864
22865pub trait SemanticsProvider {
22866    fn hover(
22867        &self,
22868        buffer: &Entity<Buffer>,
22869        position: text::Anchor,
22870        cx: &mut App,
22871    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22872
22873    fn inline_values(
22874        &self,
22875        buffer_handle: Entity<Buffer>,
22876        range: Range<text::Anchor>,
22877        cx: &mut App,
22878    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22879
22880    fn inlay_hints(
22881        &self,
22882        buffer_handle: Entity<Buffer>,
22883        range: Range<text::Anchor>,
22884        cx: &mut App,
22885    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22886
22887    fn resolve_inlay_hint(
22888        &self,
22889        hint: InlayHint,
22890        buffer_handle: Entity<Buffer>,
22891        server_id: LanguageServerId,
22892        cx: &mut App,
22893    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22894
22895    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22896
22897    fn document_highlights(
22898        &self,
22899        buffer: &Entity<Buffer>,
22900        position: text::Anchor,
22901        cx: &mut App,
22902    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22903
22904    fn definitions(
22905        &self,
22906        buffer: &Entity<Buffer>,
22907        position: text::Anchor,
22908        kind: GotoDefinitionKind,
22909        cx: &mut App,
22910    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22911
22912    fn range_for_rename(
22913        &self,
22914        buffer: &Entity<Buffer>,
22915        position: text::Anchor,
22916        cx: &mut App,
22917    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22918
22919    fn perform_rename(
22920        &self,
22921        buffer: &Entity<Buffer>,
22922        position: text::Anchor,
22923        new_name: String,
22924        cx: &mut App,
22925    ) -> Option<Task<Result<ProjectTransaction>>>;
22926}
22927
22928pub trait CompletionProvider {
22929    fn completions(
22930        &self,
22931        excerpt_id: ExcerptId,
22932        buffer: &Entity<Buffer>,
22933        buffer_position: text::Anchor,
22934        trigger: CompletionContext,
22935        window: &mut Window,
22936        cx: &mut Context<Editor>,
22937    ) -> Task<Result<Vec<CompletionResponse>>>;
22938
22939    fn resolve_completions(
22940        &self,
22941        _buffer: Entity<Buffer>,
22942        _completion_indices: Vec<usize>,
22943        _completions: Rc<RefCell<Box<[Completion]>>>,
22944        _cx: &mut Context<Editor>,
22945    ) -> Task<Result<bool>> {
22946        Task::ready(Ok(false))
22947    }
22948
22949    fn apply_additional_edits_for_completion(
22950        &self,
22951        _buffer: Entity<Buffer>,
22952        _completions: Rc<RefCell<Box<[Completion]>>>,
22953        _completion_index: usize,
22954        _push_to_history: bool,
22955        _cx: &mut Context<Editor>,
22956    ) -> Task<Result<Option<language::Transaction>>> {
22957        Task::ready(Ok(None))
22958    }
22959
22960    fn is_completion_trigger(
22961        &self,
22962        buffer: &Entity<Buffer>,
22963        position: language::Anchor,
22964        text: &str,
22965        trigger_in_words: bool,
22966        menu_is_open: bool,
22967        cx: &mut Context<Editor>,
22968    ) -> bool;
22969
22970    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22971
22972    fn sort_completions(&self) -> bool {
22973        true
22974    }
22975
22976    fn filter_completions(&self) -> bool {
22977        true
22978    }
22979}
22980
22981pub trait CodeActionProvider {
22982    fn id(&self) -> Arc<str>;
22983
22984    fn code_actions(
22985        &self,
22986        buffer: &Entity<Buffer>,
22987        range: Range<text::Anchor>,
22988        window: &mut Window,
22989        cx: &mut App,
22990    ) -> Task<Result<Vec<CodeAction>>>;
22991
22992    fn apply_code_action(
22993        &self,
22994        buffer_handle: Entity<Buffer>,
22995        action: CodeAction,
22996        excerpt_id: ExcerptId,
22997        push_to_history: bool,
22998        window: &mut Window,
22999        cx: &mut App,
23000    ) -> Task<Result<ProjectTransaction>>;
23001}
23002
23003impl CodeActionProvider for Entity<Project> {
23004    fn id(&self) -> Arc<str> {
23005        "project".into()
23006    }
23007
23008    fn code_actions(
23009        &self,
23010        buffer: &Entity<Buffer>,
23011        range: Range<text::Anchor>,
23012        _window: &mut Window,
23013        cx: &mut App,
23014    ) -> Task<Result<Vec<CodeAction>>> {
23015        self.update(cx, |project, cx| {
23016            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23017            let code_actions = project.code_actions(buffer, range, None, cx);
23018            cx.background_spawn(async move {
23019                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23020                Ok(code_lens_actions
23021                    .context("code lens fetch")?
23022                    .into_iter()
23023                    .flatten()
23024                    .chain(
23025                        code_actions
23026                            .context("code action fetch")?
23027                            .into_iter()
23028                            .flatten(),
23029                    )
23030                    .collect())
23031            })
23032        })
23033    }
23034
23035    fn apply_code_action(
23036        &self,
23037        buffer_handle: Entity<Buffer>,
23038        action: CodeAction,
23039        _excerpt_id: ExcerptId,
23040        push_to_history: bool,
23041        _window: &mut Window,
23042        cx: &mut App,
23043    ) -> Task<Result<ProjectTransaction>> {
23044        self.update(cx, |project, cx| {
23045            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23046        })
23047    }
23048}
23049
23050fn snippet_completions(
23051    project: &Project,
23052    buffer: &Entity<Buffer>,
23053    buffer_position: text::Anchor,
23054    cx: &mut App,
23055) -> Task<Result<CompletionResponse>> {
23056    let languages = buffer.read(cx).languages_at(buffer_position);
23057    let snippet_store = project.snippets().read(cx);
23058
23059    let scopes: Vec<_> = languages
23060        .iter()
23061        .filter_map(|language| {
23062            let language_name = language.lsp_id();
23063            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23064
23065            if snippets.is_empty() {
23066                None
23067            } else {
23068                Some((language.default_scope(), snippets))
23069            }
23070        })
23071        .collect();
23072
23073    if scopes.is_empty() {
23074        return Task::ready(Ok(CompletionResponse {
23075            completions: vec![],
23076            display_options: CompletionDisplayOptions::default(),
23077            is_incomplete: false,
23078        }));
23079    }
23080
23081    let snapshot = buffer.read(cx).text_snapshot();
23082    let executor = cx.background_executor().clone();
23083
23084    cx.background_spawn(async move {
23085        let mut is_incomplete = false;
23086        let mut completions: Vec<Completion> = Vec::new();
23087        for (scope, snippets) in scopes.into_iter() {
23088            let classifier =
23089                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23090
23091            const MAX_WORD_PREFIX_LEN: usize = 128;
23092            let last_word: String = snapshot
23093                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23094                .take(MAX_WORD_PREFIX_LEN)
23095                .take_while(|c| classifier.is_word(*c))
23096                .collect::<String>()
23097                .chars()
23098                .rev()
23099                .collect();
23100
23101            if last_word.is_empty() {
23102                return Ok(CompletionResponse {
23103                    completions: vec![],
23104                    display_options: CompletionDisplayOptions::default(),
23105                    is_incomplete: true,
23106                });
23107            }
23108
23109            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23110            let to_lsp = |point: &text::Anchor| {
23111                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23112                point_to_lsp(end)
23113            };
23114            let lsp_end = to_lsp(&buffer_position);
23115
23116            let candidates = snippets
23117                .iter()
23118                .enumerate()
23119                .flat_map(|(ix, snippet)| {
23120                    snippet
23121                        .prefix
23122                        .iter()
23123                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23124                })
23125                .collect::<Vec<StringMatchCandidate>>();
23126
23127            const MAX_RESULTS: usize = 100;
23128            let mut matches = fuzzy::match_strings(
23129                &candidates,
23130                &last_word,
23131                last_word.chars().any(|c| c.is_uppercase()),
23132                true,
23133                MAX_RESULTS,
23134                &Default::default(),
23135                executor.clone(),
23136            )
23137            .await;
23138
23139            if matches.len() >= MAX_RESULTS {
23140                is_incomplete = true;
23141            }
23142
23143            // Remove all candidates where the query's start does not match the start of any word in the candidate
23144            if let Some(query_start) = last_word.chars().next() {
23145                matches.retain(|string_match| {
23146                    split_words(&string_match.string).any(|word| {
23147                        // Check that the first codepoint of the word as lowercase matches the first
23148                        // codepoint of the query as lowercase
23149                        word.chars()
23150                            .flat_map(|codepoint| codepoint.to_lowercase())
23151                            .zip(query_start.to_lowercase())
23152                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23153                    })
23154                });
23155            }
23156
23157            let matched_strings = matches
23158                .into_iter()
23159                .map(|m| m.string)
23160                .collect::<HashSet<_>>();
23161
23162            completions.extend(snippets.iter().filter_map(|snippet| {
23163                let matching_prefix = snippet
23164                    .prefix
23165                    .iter()
23166                    .find(|prefix| matched_strings.contains(*prefix))?;
23167                let start = as_offset - last_word.len();
23168                let start = snapshot.anchor_before(start);
23169                let range = start..buffer_position;
23170                let lsp_start = to_lsp(&start);
23171                let lsp_range = lsp::Range {
23172                    start: lsp_start,
23173                    end: lsp_end,
23174                };
23175                Some(Completion {
23176                    replace_range: range,
23177                    new_text: snippet.body.clone(),
23178                    source: CompletionSource::Lsp {
23179                        insert_range: None,
23180                        server_id: LanguageServerId(usize::MAX),
23181                        resolved: true,
23182                        lsp_completion: Box::new(lsp::CompletionItem {
23183                            label: snippet.prefix.first().unwrap().clone(),
23184                            kind: Some(CompletionItemKind::SNIPPET),
23185                            label_details: snippet.description.as_ref().map(|description| {
23186                                lsp::CompletionItemLabelDetails {
23187                                    detail: Some(description.clone()),
23188                                    description: None,
23189                                }
23190                            }),
23191                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23192                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23193                                lsp::InsertReplaceEdit {
23194                                    new_text: snippet.body.clone(),
23195                                    insert: lsp_range,
23196                                    replace: lsp_range,
23197                                },
23198                            )),
23199                            filter_text: Some(snippet.body.clone()),
23200                            sort_text: Some(char::MAX.to_string()),
23201                            ..lsp::CompletionItem::default()
23202                        }),
23203                        lsp_defaults: None,
23204                    },
23205                    label: CodeLabel::plain(matching_prefix.clone(), None),
23206                    icon_path: None,
23207                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23208                        single_line: snippet.name.clone().into(),
23209                        plain_text: snippet
23210                            .description
23211                            .clone()
23212                            .map(|description| description.into()),
23213                    }),
23214                    insert_text_mode: None,
23215                    confirm: None,
23216                })
23217            }))
23218        }
23219
23220        Ok(CompletionResponse {
23221            completions,
23222            display_options: CompletionDisplayOptions::default(),
23223            is_incomplete,
23224        })
23225    })
23226}
23227
23228impl CompletionProvider for Entity<Project> {
23229    fn completions(
23230        &self,
23231        _excerpt_id: ExcerptId,
23232        buffer: &Entity<Buffer>,
23233        buffer_position: text::Anchor,
23234        options: CompletionContext,
23235        _window: &mut Window,
23236        cx: &mut Context<Editor>,
23237    ) -> Task<Result<Vec<CompletionResponse>>> {
23238        self.update(cx, |project, cx| {
23239            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23240            let project_completions = project.completions(buffer, buffer_position, options, cx);
23241            cx.background_spawn(async move {
23242                let mut responses = project_completions.await?;
23243                let snippets = snippets.await?;
23244                if !snippets.completions.is_empty() {
23245                    responses.push(snippets);
23246                }
23247                Ok(responses)
23248            })
23249        })
23250    }
23251
23252    fn resolve_completions(
23253        &self,
23254        buffer: Entity<Buffer>,
23255        completion_indices: Vec<usize>,
23256        completions: Rc<RefCell<Box<[Completion]>>>,
23257        cx: &mut Context<Editor>,
23258    ) -> Task<Result<bool>> {
23259        self.update(cx, |project, cx| {
23260            project.lsp_store().update(cx, |lsp_store, cx| {
23261                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23262            })
23263        })
23264    }
23265
23266    fn apply_additional_edits_for_completion(
23267        &self,
23268        buffer: Entity<Buffer>,
23269        completions: Rc<RefCell<Box<[Completion]>>>,
23270        completion_index: usize,
23271        push_to_history: bool,
23272        cx: &mut Context<Editor>,
23273    ) -> Task<Result<Option<language::Transaction>>> {
23274        self.update(cx, |project, cx| {
23275            project.lsp_store().update(cx, |lsp_store, cx| {
23276                lsp_store.apply_additional_edits_for_completion(
23277                    buffer,
23278                    completions,
23279                    completion_index,
23280                    push_to_history,
23281                    cx,
23282                )
23283            })
23284        })
23285    }
23286
23287    fn is_completion_trigger(
23288        &self,
23289        buffer: &Entity<Buffer>,
23290        position: language::Anchor,
23291        text: &str,
23292        trigger_in_words: bool,
23293        menu_is_open: bool,
23294        cx: &mut Context<Editor>,
23295    ) -> bool {
23296        let mut chars = text.chars();
23297        let char = if let Some(char) = chars.next() {
23298            char
23299        } else {
23300            return false;
23301        };
23302        if chars.next().is_some() {
23303            return false;
23304        }
23305
23306        let buffer = buffer.read(cx);
23307        let snapshot = buffer.snapshot();
23308        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23309            return false;
23310        }
23311        let classifier = snapshot
23312            .char_classifier_at(position)
23313            .scope_context(Some(CharScopeContext::Completion));
23314        if trigger_in_words && classifier.is_word(char) {
23315            return true;
23316        }
23317
23318        buffer.completion_triggers().contains(text)
23319    }
23320}
23321
23322impl SemanticsProvider for Entity<Project> {
23323    fn hover(
23324        &self,
23325        buffer: &Entity<Buffer>,
23326        position: text::Anchor,
23327        cx: &mut App,
23328    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23329        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23330    }
23331
23332    fn document_highlights(
23333        &self,
23334        buffer: &Entity<Buffer>,
23335        position: text::Anchor,
23336        cx: &mut App,
23337    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23338        Some(self.update(cx, |project, cx| {
23339            project.document_highlights(buffer, position, cx)
23340        }))
23341    }
23342
23343    fn definitions(
23344        &self,
23345        buffer: &Entity<Buffer>,
23346        position: text::Anchor,
23347        kind: GotoDefinitionKind,
23348        cx: &mut App,
23349    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23350        Some(self.update(cx, |project, cx| match kind {
23351            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23352            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23353            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23354            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23355        }))
23356    }
23357
23358    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23359        self.update(cx, |project, cx| {
23360            if project
23361                .active_debug_session(cx)
23362                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23363            {
23364                return true;
23365            }
23366
23367            buffer.update(cx, |buffer, cx| {
23368                project.any_language_server_supports_inlay_hints(buffer, cx)
23369            })
23370        })
23371    }
23372
23373    fn inline_values(
23374        &self,
23375        buffer_handle: Entity<Buffer>,
23376        range: Range<text::Anchor>,
23377        cx: &mut App,
23378    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23379        self.update(cx, |project, cx| {
23380            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23381
23382            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23383        })
23384    }
23385
23386    fn inlay_hints(
23387        &self,
23388        buffer_handle: Entity<Buffer>,
23389        range: Range<text::Anchor>,
23390        cx: &mut App,
23391    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23392        Some(self.update(cx, |project, cx| {
23393            project.inlay_hints(buffer_handle, range, cx)
23394        }))
23395    }
23396
23397    fn resolve_inlay_hint(
23398        &self,
23399        hint: InlayHint,
23400        buffer_handle: Entity<Buffer>,
23401        server_id: LanguageServerId,
23402        cx: &mut App,
23403    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23404        Some(self.update(cx, |project, cx| {
23405            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23406        }))
23407    }
23408
23409    fn range_for_rename(
23410        &self,
23411        buffer: &Entity<Buffer>,
23412        position: text::Anchor,
23413        cx: &mut App,
23414    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23415        Some(self.update(cx, |project, cx| {
23416            let buffer = buffer.clone();
23417            let task = project.prepare_rename(buffer.clone(), position, cx);
23418            cx.spawn(async move |_, cx| {
23419                Ok(match task.await? {
23420                    PrepareRenameResponse::Success(range) => Some(range),
23421                    PrepareRenameResponse::InvalidPosition => None,
23422                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23423                        // Fallback on using TreeSitter info to determine identifier range
23424                        buffer.read_with(cx, |buffer, _| {
23425                            let snapshot = buffer.snapshot();
23426                            let (range, kind) = snapshot.surrounding_word(position, None);
23427                            if kind != Some(CharKind::Word) {
23428                                return None;
23429                            }
23430                            Some(
23431                                snapshot.anchor_before(range.start)
23432                                    ..snapshot.anchor_after(range.end),
23433                            )
23434                        })?
23435                    }
23436                })
23437            })
23438        }))
23439    }
23440
23441    fn perform_rename(
23442        &self,
23443        buffer: &Entity<Buffer>,
23444        position: text::Anchor,
23445        new_name: String,
23446        cx: &mut App,
23447    ) -> Option<Task<Result<ProjectTransaction>>> {
23448        Some(self.update(cx, |project, cx| {
23449            project.perform_rename(buffer.clone(), position, new_name, cx)
23450        }))
23451    }
23452}
23453
23454fn inlay_hint_settings(
23455    location: Anchor,
23456    snapshot: &MultiBufferSnapshot,
23457    cx: &mut Context<Editor>,
23458) -> InlayHintSettings {
23459    let file = snapshot.file_at(location);
23460    let language = snapshot.language_at(location).map(|l| l.name());
23461    language_settings(language, file, cx).inlay_hints
23462}
23463
23464fn consume_contiguous_rows(
23465    contiguous_row_selections: &mut Vec<Selection<Point>>,
23466    selection: &Selection<Point>,
23467    display_map: &DisplaySnapshot,
23468    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23469) -> (MultiBufferRow, MultiBufferRow) {
23470    contiguous_row_selections.push(selection.clone());
23471    let start_row = starting_row(selection, display_map);
23472    let mut end_row = ending_row(selection, display_map);
23473
23474    while let Some(next_selection) = selections.peek() {
23475        if next_selection.start.row <= end_row.0 {
23476            end_row = ending_row(next_selection, display_map);
23477            contiguous_row_selections.push(selections.next().unwrap().clone());
23478        } else {
23479            break;
23480        }
23481    }
23482    (start_row, end_row)
23483}
23484
23485fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23486    if selection.start.column > 0 {
23487        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23488    } else {
23489        MultiBufferRow(selection.start.row)
23490    }
23491}
23492
23493fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23494    if next_selection.end.column > 0 || next_selection.is_empty() {
23495        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23496    } else {
23497        MultiBufferRow(next_selection.end.row)
23498    }
23499}
23500
23501impl EditorSnapshot {
23502    pub fn remote_selections_in_range<'a>(
23503        &'a self,
23504        range: &'a Range<Anchor>,
23505        collaboration_hub: &dyn CollaborationHub,
23506        cx: &'a App,
23507    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23508        let participant_names = collaboration_hub.user_names(cx);
23509        let participant_indices = collaboration_hub.user_participant_indices(cx);
23510        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23511        let collaborators_by_replica_id = collaborators_by_peer_id
23512            .values()
23513            .map(|collaborator| (collaborator.replica_id, collaborator))
23514            .collect::<HashMap<_, _>>();
23515        self.buffer_snapshot()
23516            .selections_in_range(range, false)
23517            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23518                if replica_id == ReplicaId::AGENT {
23519                    Some(RemoteSelection {
23520                        replica_id,
23521                        selection,
23522                        cursor_shape,
23523                        line_mode,
23524                        collaborator_id: CollaboratorId::Agent,
23525                        user_name: Some("Agent".into()),
23526                        color: cx.theme().players().agent(),
23527                    })
23528                } else {
23529                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23530                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23531                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23532                    Some(RemoteSelection {
23533                        replica_id,
23534                        selection,
23535                        cursor_shape,
23536                        line_mode,
23537                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23538                        user_name,
23539                        color: if let Some(index) = participant_index {
23540                            cx.theme().players().color_for_participant(index.0)
23541                        } else {
23542                            cx.theme().players().absent()
23543                        },
23544                    })
23545                }
23546            })
23547    }
23548
23549    pub fn hunks_for_ranges(
23550        &self,
23551        ranges: impl IntoIterator<Item = Range<Point>>,
23552    ) -> Vec<MultiBufferDiffHunk> {
23553        let mut hunks = Vec::new();
23554        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23555            HashMap::default();
23556        for query_range in ranges {
23557            let query_rows =
23558                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23559            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23560                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23561            ) {
23562                // Include deleted hunks that are adjacent to the query range, because
23563                // otherwise they would be missed.
23564                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23565                if hunk.status().is_deleted() {
23566                    intersects_range |= hunk.row_range.start == query_rows.end;
23567                    intersects_range |= hunk.row_range.end == query_rows.start;
23568                }
23569                if intersects_range {
23570                    if !processed_buffer_rows
23571                        .entry(hunk.buffer_id)
23572                        .or_default()
23573                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23574                    {
23575                        continue;
23576                    }
23577                    hunks.push(hunk);
23578                }
23579            }
23580        }
23581
23582        hunks
23583    }
23584
23585    fn display_diff_hunks_for_rows<'a>(
23586        &'a self,
23587        display_rows: Range<DisplayRow>,
23588        folded_buffers: &'a HashSet<BufferId>,
23589    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23590        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23591        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23592
23593        self.buffer_snapshot()
23594            .diff_hunks_in_range(buffer_start..buffer_end)
23595            .filter_map(|hunk| {
23596                if folded_buffers.contains(&hunk.buffer_id) {
23597                    return None;
23598                }
23599
23600                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23601                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23602
23603                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23604                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23605
23606                let display_hunk = if hunk_display_start.column() != 0 {
23607                    DisplayDiffHunk::Folded {
23608                        display_row: hunk_display_start.row(),
23609                    }
23610                } else {
23611                    let mut end_row = hunk_display_end.row();
23612                    if hunk_display_end.column() > 0 {
23613                        end_row.0 += 1;
23614                    }
23615                    let is_created_file = hunk.is_created_file();
23616                    DisplayDiffHunk::Unfolded {
23617                        status: hunk.status(),
23618                        diff_base_byte_range: hunk.diff_base_byte_range,
23619                        display_row_range: hunk_display_start.row()..end_row,
23620                        multi_buffer_range: Anchor::range_in_buffer(
23621                            hunk.excerpt_id,
23622                            hunk.buffer_id,
23623                            hunk.buffer_range,
23624                        ),
23625                        is_created_file,
23626                    }
23627                };
23628
23629                Some(display_hunk)
23630            })
23631    }
23632
23633    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23634        self.display_snapshot
23635            .buffer_snapshot()
23636            .language_at(position)
23637    }
23638
23639    pub fn is_focused(&self) -> bool {
23640        self.is_focused
23641    }
23642
23643    pub fn placeholder_text(&self) -> Option<String> {
23644        self.placeholder_display_snapshot
23645            .as_ref()
23646            .map(|display_map| display_map.text())
23647    }
23648
23649    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23650        self.scroll_anchor.scroll_position(&self.display_snapshot)
23651    }
23652
23653    fn gutter_dimensions(
23654        &self,
23655        font_id: FontId,
23656        font_size: Pixels,
23657        max_line_number_width: Pixels,
23658        cx: &App,
23659    ) -> Option<GutterDimensions> {
23660        if !self.show_gutter {
23661            return None;
23662        }
23663
23664        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23665        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23666
23667        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23668            matches!(
23669                ProjectSettings::get_global(cx).git.git_gutter,
23670                GitGutterSetting::TrackedFiles
23671            )
23672        });
23673        let gutter_settings = EditorSettings::get_global(cx).gutter;
23674        let show_line_numbers = self
23675            .show_line_numbers
23676            .unwrap_or(gutter_settings.line_numbers);
23677        let line_gutter_width = if show_line_numbers {
23678            // Avoid flicker-like gutter resizes when the line number gains another digit by
23679            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23680            let min_width_for_number_on_gutter =
23681                ch_advance * gutter_settings.min_line_number_digits as f32;
23682            max_line_number_width.max(min_width_for_number_on_gutter)
23683        } else {
23684            0.0.into()
23685        };
23686
23687        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23688        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23689
23690        let git_blame_entries_width =
23691            self.git_blame_gutter_max_author_length
23692                .map(|max_author_length| {
23693                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23694                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23695
23696                    /// The number of characters to dedicate to gaps and margins.
23697                    const SPACING_WIDTH: usize = 4;
23698
23699                    let max_char_count = max_author_length.min(renderer.max_author_length())
23700                        + ::git::SHORT_SHA_LENGTH
23701                        + MAX_RELATIVE_TIMESTAMP.len()
23702                        + SPACING_WIDTH;
23703
23704                    ch_advance * max_char_count
23705                });
23706
23707        let is_singleton = self.buffer_snapshot().is_singleton();
23708
23709        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23710        left_padding += if !is_singleton {
23711            ch_width * 4.0
23712        } else if show_runnables || show_breakpoints {
23713            ch_width * 3.0
23714        } else if show_git_gutter && show_line_numbers {
23715            ch_width * 2.0
23716        } else if show_git_gutter || show_line_numbers {
23717            ch_width
23718        } else {
23719            px(0.)
23720        };
23721
23722        let shows_folds = is_singleton && gutter_settings.folds;
23723
23724        let right_padding = if shows_folds && show_line_numbers {
23725            ch_width * 4.0
23726        } else if shows_folds || (!is_singleton && show_line_numbers) {
23727            ch_width * 3.0
23728        } else if show_line_numbers {
23729            ch_width
23730        } else {
23731            px(0.)
23732        };
23733
23734        Some(GutterDimensions {
23735            left_padding,
23736            right_padding,
23737            width: line_gutter_width + left_padding + right_padding,
23738            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23739            git_blame_entries_width,
23740        })
23741    }
23742
23743    pub fn render_crease_toggle(
23744        &self,
23745        buffer_row: MultiBufferRow,
23746        row_contains_cursor: bool,
23747        editor: Entity<Editor>,
23748        window: &mut Window,
23749        cx: &mut App,
23750    ) -> Option<AnyElement> {
23751        let folded = self.is_line_folded(buffer_row);
23752        let mut is_foldable = false;
23753
23754        if let Some(crease) = self
23755            .crease_snapshot
23756            .query_row(buffer_row, self.buffer_snapshot())
23757        {
23758            is_foldable = true;
23759            match crease {
23760                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23761                    if let Some(render_toggle) = render_toggle {
23762                        let toggle_callback =
23763                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23764                                if folded {
23765                                    editor.update(cx, |editor, cx| {
23766                                        editor.fold_at(buffer_row, window, cx)
23767                                    });
23768                                } else {
23769                                    editor.update(cx, |editor, cx| {
23770                                        editor.unfold_at(buffer_row, window, cx)
23771                                    });
23772                                }
23773                            });
23774                        return Some((render_toggle)(
23775                            buffer_row,
23776                            folded,
23777                            toggle_callback,
23778                            window,
23779                            cx,
23780                        ));
23781                    }
23782                }
23783            }
23784        }
23785
23786        is_foldable |= self.starts_indent(buffer_row);
23787
23788        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23789            Some(
23790                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23791                    .toggle_state(folded)
23792                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23793                        if folded {
23794                            this.unfold_at(buffer_row, window, cx);
23795                        } else {
23796                            this.fold_at(buffer_row, window, cx);
23797                        }
23798                    }))
23799                    .into_any_element(),
23800            )
23801        } else {
23802            None
23803        }
23804    }
23805
23806    pub fn render_crease_trailer(
23807        &self,
23808        buffer_row: MultiBufferRow,
23809        window: &mut Window,
23810        cx: &mut App,
23811    ) -> Option<AnyElement> {
23812        let folded = self.is_line_folded(buffer_row);
23813        if let Crease::Inline { render_trailer, .. } = self
23814            .crease_snapshot
23815            .query_row(buffer_row, self.buffer_snapshot())?
23816        {
23817            let render_trailer = render_trailer.as_ref()?;
23818            Some(render_trailer(buffer_row, folded, window, cx))
23819        } else {
23820            None
23821        }
23822    }
23823}
23824
23825impl Deref for EditorSnapshot {
23826    type Target = DisplaySnapshot;
23827
23828    fn deref(&self) -> &Self::Target {
23829        &self.display_snapshot
23830    }
23831}
23832
23833#[derive(Clone, Debug, PartialEq, Eq)]
23834pub enum EditorEvent {
23835    InputIgnored {
23836        text: Arc<str>,
23837    },
23838    InputHandled {
23839        utf16_range_to_replace: Option<Range<isize>>,
23840        text: Arc<str>,
23841    },
23842    ExcerptsAdded {
23843        buffer: Entity<Buffer>,
23844        predecessor: ExcerptId,
23845        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23846    },
23847    ExcerptsRemoved {
23848        ids: Vec<ExcerptId>,
23849        removed_buffer_ids: Vec<BufferId>,
23850    },
23851    BufferFoldToggled {
23852        ids: Vec<ExcerptId>,
23853        folded: bool,
23854    },
23855    ExcerptsEdited {
23856        ids: Vec<ExcerptId>,
23857    },
23858    ExcerptsExpanded {
23859        ids: Vec<ExcerptId>,
23860    },
23861    BufferEdited,
23862    Edited {
23863        transaction_id: clock::Lamport,
23864    },
23865    Reparsed(BufferId),
23866    Focused,
23867    FocusedIn,
23868    Blurred,
23869    DirtyChanged,
23870    Saved,
23871    TitleChanged,
23872    SelectionsChanged {
23873        local: bool,
23874    },
23875    ScrollPositionChanged {
23876        local: bool,
23877        autoscroll: bool,
23878    },
23879    TransactionUndone {
23880        transaction_id: clock::Lamport,
23881    },
23882    TransactionBegun {
23883        transaction_id: clock::Lamport,
23884    },
23885    CursorShapeChanged,
23886    BreadcrumbsChanged,
23887    PushedToNavHistory {
23888        anchor: Anchor,
23889        is_deactivate: bool,
23890    },
23891}
23892
23893impl EventEmitter<EditorEvent> for Editor {}
23894
23895impl Focusable for Editor {
23896    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23897        self.focus_handle.clone()
23898    }
23899}
23900
23901impl Render for Editor {
23902    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23903        let settings = ThemeSettings::get_global(cx);
23904
23905        let mut text_style = match self.mode {
23906            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23907                color: cx.theme().colors().editor_foreground,
23908                font_family: settings.ui_font.family.clone(),
23909                font_features: settings.ui_font.features.clone(),
23910                font_fallbacks: settings.ui_font.fallbacks.clone(),
23911                font_size: rems(0.875).into(),
23912                font_weight: settings.ui_font.weight,
23913                line_height: relative(settings.buffer_line_height.value()),
23914                ..Default::default()
23915            },
23916            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23917                color: cx.theme().colors().editor_foreground,
23918                font_family: settings.buffer_font.family.clone(),
23919                font_features: settings.buffer_font.features.clone(),
23920                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23921                font_size: settings.buffer_font_size(cx).into(),
23922                font_weight: settings.buffer_font.weight,
23923                line_height: relative(settings.buffer_line_height.value()),
23924                ..Default::default()
23925            },
23926        };
23927        if let Some(text_style_refinement) = &self.text_style_refinement {
23928            text_style.refine(text_style_refinement)
23929        }
23930
23931        let background = match self.mode {
23932            EditorMode::SingleLine => cx.theme().system().transparent,
23933            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23934            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23935            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23936        };
23937
23938        EditorElement::new(
23939            &cx.entity(),
23940            EditorStyle {
23941                background,
23942                border: cx.theme().colors().border,
23943                local_player: cx.theme().players().local(),
23944                text: text_style,
23945                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23946                syntax: cx.theme().syntax().clone(),
23947                status: cx.theme().status().clone(),
23948                inlay_hints_style: make_inlay_hints_style(cx),
23949                edit_prediction_styles: make_suggestion_styles(cx),
23950                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23951                show_underlines: self.diagnostics_enabled(),
23952            },
23953        )
23954    }
23955}
23956
23957impl EntityInputHandler for Editor {
23958    fn text_for_range(
23959        &mut self,
23960        range_utf16: Range<usize>,
23961        adjusted_range: &mut Option<Range<usize>>,
23962        _: &mut Window,
23963        cx: &mut Context<Self>,
23964    ) -> Option<String> {
23965        let snapshot = self.buffer.read(cx).read(cx);
23966        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23967        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23968        if (start.0..end.0) != range_utf16 {
23969            adjusted_range.replace(start.0..end.0);
23970        }
23971        Some(snapshot.text_for_range(start..end).collect())
23972    }
23973
23974    fn selected_text_range(
23975        &mut self,
23976        ignore_disabled_input: bool,
23977        _: &mut Window,
23978        cx: &mut Context<Self>,
23979    ) -> Option<UTF16Selection> {
23980        // Prevent the IME menu from appearing when holding down an alphabetic key
23981        // while input is disabled.
23982        if !ignore_disabled_input && !self.input_enabled {
23983            return None;
23984        }
23985
23986        let selection = self
23987            .selections
23988            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23989        let range = selection.range();
23990
23991        Some(UTF16Selection {
23992            range: range.start.0..range.end.0,
23993            reversed: selection.reversed,
23994        })
23995    }
23996
23997    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23998        let snapshot = self.buffer.read(cx).read(cx);
23999        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24000        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24001    }
24002
24003    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24004        self.clear_highlights::<InputComposition>(cx);
24005        self.ime_transaction.take();
24006    }
24007
24008    fn replace_text_in_range(
24009        &mut self,
24010        range_utf16: Option<Range<usize>>,
24011        text: &str,
24012        window: &mut Window,
24013        cx: &mut Context<Self>,
24014    ) {
24015        if !self.input_enabled {
24016            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24017            return;
24018        }
24019
24020        self.transact(window, cx, |this, window, cx| {
24021            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24022                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24023                Some(this.selection_replacement_ranges(range_utf16, cx))
24024            } else {
24025                this.marked_text_ranges(cx)
24026            };
24027
24028            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24029                let newest_selection_id = this.selections.newest_anchor().id;
24030                this.selections
24031                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24032                    .iter()
24033                    .zip(ranges_to_replace.iter())
24034                    .find_map(|(selection, range)| {
24035                        if selection.id == newest_selection_id {
24036                            Some(
24037                                (range.start.0 as isize - selection.head().0 as isize)
24038                                    ..(range.end.0 as isize - selection.head().0 as isize),
24039                            )
24040                        } else {
24041                            None
24042                        }
24043                    })
24044            });
24045
24046            cx.emit(EditorEvent::InputHandled {
24047                utf16_range_to_replace: range_to_replace,
24048                text: text.into(),
24049            });
24050
24051            if let Some(new_selected_ranges) = new_selected_ranges {
24052                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24053                    selections.select_ranges(new_selected_ranges)
24054                });
24055                this.backspace(&Default::default(), window, cx);
24056            }
24057
24058            this.handle_input(text, window, cx);
24059        });
24060
24061        if let Some(transaction) = self.ime_transaction {
24062            self.buffer.update(cx, |buffer, cx| {
24063                buffer.group_until_transaction(transaction, cx);
24064            });
24065        }
24066
24067        self.unmark_text(window, cx);
24068    }
24069
24070    fn replace_and_mark_text_in_range(
24071        &mut self,
24072        range_utf16: Option<Range<usize>>,
24073        text: &str,
24074        new_selected_range_utf16: Option<Range<usize>>,
24075        window: &mut Window,
24076        cx: &mut Context<Self>,
24077    ) {
24078        if !self.input_enabled {
24079            return;
24080        }
24081
24082        let transaction = self.transact(window, cx, |this, window, cx| {
24083            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24084                let snapshot = this.buffer.read(cx).read(cx);
24085                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24086                    for marked_range in &mut marked_ranges {
24087                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24088                        marked_range.start.0 += relative_range_utf16.start;
24089                        marked_range.start =
24090                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24091                        marked_range.end =
24092                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24093                    }
24094                }
24095                Some(marked_ranges)
24096            } else if let Some(range_utf16) = range_utf16 {
24097                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24098                Some(this.selection_replacement_ranges(range_utf16, cx))
24099            } else {
24100                None
24101            };
24102
24103            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24104                let newest_selection_id = this.selections.newest_anchor().id;
24105                this.selections
24106                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24107                    .iter()
24108                    .zip(ranges_to_replace.iter())
24109                    .find_map(|(selection, range)| {
24110                        if selection.id == newest_selection_id {
24111                            Some(
24112                                (range.start.0 as isize - selection.head().0 as isize)
24113                                    ..(range.end.0 as isize - selection.head().0 as isize),
24114                            )
24115                        } else {
24116                            None
24117                        }
24118                    })
24119            });
24120
24121            cx.emit(EditorEvent::InputHandled {
24122                utf16_range_to_replace: range_to_replace,
24123                text: text.into(),
24124            });
24125
24126            if let Some(ranges) = ranges_to_replace {
24127                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24128                    s.select_ranges(ranges)
24129                });
24130            }
24131
24132            let marked_ranges = {
24133                let snapshot = this.buffer.read(cx).read(cx);
24134                this.selections
24135                    .disjoint_anchors_arc()
24136                    .iter()
24137                    .map(|selection| {
24138                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24139                    })
24140                    .collect::<Vec<_>>()
24141            };
24142
24143            if text.is_empty() {
24144                this.unmark_text(window, cx);
24145            } else {
24146                this.highlight_text::<InputComposition>(
24147                    marked_ranges.clone(),
24148                    HighlightStyle {
24149                        underline: Some(UnderlineStyle {
24150                            thickness: px(1.),
24151                            color: None,
24152                            wavy: false,
24153                        }),
24154                        ..Default::default()
24155                    },
24156                    cx,
24157                );
24158            }
24159
24160            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24161            let use_autoclose = this.use_autoclose;
24162            let use_auto_surround = this.use_auto_surround;
24163            this.set_use_autoclose(false);
24164            this.set_use_auto_surround(false);
24165            this.handle_input(text, window, cx);
24166            this.set_use_autoclose(use_autoclose);
24167            this.set_use_auto_surround(use_auto_surround);
24168
24169            if let Some(new_selected_range) = new_selected_range_utf16 {
24170                let snapshot = this.buffer.read(cx).read(cx);
24171                let new_selected_ranges = marked_ranges
24172                    .into_iter()
24173                    .map(|marked_range| {
24174                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24175                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24176                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24177                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24178                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24179                    })
24180                    .collect::<Vec<_>>();
24181
24182                drop(snapshot);
24183                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24184                    selections.select_ranges(new_selected_ranges)
24185                });
24186            }
24187        });
24188
24189        self.ime_transaction = self.ime_transaction.or(transaction);
24190        if let Some(transaction) = self.ime_transaction {
24191            self.buffer.update(cx, |buffer, cx| {
24192                buffer.group_until_transaction(transaction, cx);
24193            });
24194        }
24195
24196        if self.text_highlights::<InputComposition>(cx).is_none() {
24197            self.ime_transaction.take();
24198        }
24199    }
24200
24201    fn bounds_for_range(
24202        &mut self,
24203        range_utf16: Range<usize>,
24204        element_bounds: gpui::Bounds<Pixels>,
24205        window: &mut Window,
24206        cx: &mut Context<Self>,
24207    ) -> Option<gpui::Bounds<Pixels>> {
24208        let text_layout_details = self.text_layout_details(window);
24209        let CharacterDimensions {
24210            em_width,
24211            em_advance,
24212            line_height,
24213        } = self.character_dimensions(window);
24214
24215        let snapshot = self.snapshot(window, cx);
24216        let scroll_position = snapshot.scroll_position();
24217        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24218
24219        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24220        let x = Pixels::from(
24221            ScrollOffset::from(
24222                snapshot.x_for_display_point(start, &text_layout_details)
24223                    + self.gutter_dimensions.full_width(),
24224            ) - scroll_left,
24225        );
24226        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24227
24228        Some(Bounds {
24229            origin: element_bounds.origin + point(x, y),
24230            size: size(em_width, line_height),
24231        })
24232    }
24233
24234    fn character_index_for_point(
24235        &mut self,
24236        point: gpui::Point<Pixels>,
24237        _window: &mut Window,
24238        _cx: &mut Context<Self>,
24239    ) -> Option<usize> {
24240        let position_map = self.last_position_map.as_ref()?;
24241        if !position_map.text_hitbox.contains(&point) {
24242            return None;
24243        }
24244        let display_point = position_map.point_for_position(point).previous_valid;
24245        let anchor = position_map
24246            .snapshot
24247            .display_point_to_anchor(display_point, Bias::Left);
24248        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24249        Some(utf16_offset.0)
24250    }
24251}
24252
24253trait SelectionExt {
24254    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24255    fn spanned_rows(
24256        &self,
24257        include_end_if_at_line_start: bool,
24258        map: &DisplaySnapshot,
24259    ) -> Range<MultiBufferRow>;
24260}
24261
24262impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24263    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24264        let start = self
24265            .start
24266            .to_point(map.buffer_snapshot())
24267            .to_display_point(map);
24268        let end = self
24269            .end
24270            .to_point(map.buffer_snapshot())
24271            .to_display_point(map);
24272        if self.reversed {
24273            end..start
24274        } else {
24275            start..end
24276        }
24277    }
24278
24279    fn spanned_rows(
24280        &self,
24281        include_end_if_at_line_start: bool,
24282        map: &DisplaySnapshot,
24283    ) -> Range<MultiBufferRow> {
24284        let start = self.start.to_point(map.buffer_snapshot());
24285        let mut end = self.end.to_point(map.buffer_snapshot());
24286        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24287            end.row -= 1;
24288        }
24289
24290        let buffer_start = map.prev_line_boundary(start).0;
24291        let buffer_end = map.next_line_boundary(end).0;
24292        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24293    }
24294}
24295
24296impl<T: InvalidationRegion> InvalidationStack<T> {
24297    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24298    where
24299        S: Clone + ToOffset,
24300    {
24301        while let Some(region) = self.last() {
24302            let all_selections_inside_invalidation_ranges =
24303                if selections.len() == region.ranges().len() {
24304                    selections
24305                        .iter()
24306                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24307                        .all(|(selection, invalidation_range)| {
24308                            let head = selection.head().to_offset(buffer);
24309                            invalidation_range.start <= head && invalidation_range.end >= head
24310                        })
24311                } else {
24312                    false
24313                };
24314
24315            if all_selections_inside_invalidation_ranges {
24316                break;
24317            } else {
24318                self.pop();
24319            }
24320        }
24321    }
24322}
24323
24324impl<T> Default for InvalidationStack<T> {
24325    fn default() -> Self {
24326        Self(Default::default())
24327    }
24328}
24329
24330impl<T> Deref for InvalidationStack<T> {
24331    type Target = Vec<T>;
24332
24333    fn deref(&self) -> &Self::Target {
24334        &self.0
24335    }
24336}
24337
24338impl<T> DerefMut for InvalidationStack<T> {
24339    fn deref_mut(&mut self) -> &mut Self::Target {
24340        &mut self.0
24341    }
24342}
24343
24344impl InvalidationRegion for SnippetState {
24345    fn ranges(&self) -> &[Range<Anchor>] {
24346        &self.ranges[self.active_index]
24347    }
24348}
24349
24350fn edit_prediction_edit_text(
24351    current_snapshot: &BufferSnapshot,
24352    edits: &[(Range<Anchor>, String)],
24353    edit_preview: &EditPreview,
24354    include_deletions: bool,
24355    cx: &App,
24356) -> HighlightedText {
24357    let edits = edits
24358        .iter()
24359        .map(|(anchor, text)| {
24360            (
24361                anchor.start.text_anchor..anchor.end.text_anchor,
24362                text.clone(),
24363            )
24364        })
24365        .collect::<Vec<_>>();
24366
24367    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24368}
24369
24370fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24371    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24372    // Just show the raw edit text with basic styling
24373    let mut text = String::new();
24374    let mut highlights = Vec::new();
24375
24376    let insertion_highlight_style = HighlightStyle {
24377        color: Some(cx.theme().colors().text),
24378        ..Default::default()
24379    };
24380
24381    for (_, edit_text) in edits {
24382        let start_offset = text.len();
24383        text.push_str(edit_text);
24384        let end_offset = text.len();
24385
24386        if start_offset < end_offset {
24387            highlights.push((start_offset..end_offset, insertion_highlight_style));
24388        }
24389    }
24390
24391    HighlightedText {
24392        text: text.into(),
24393        highlights,
24394    }
24395}
24396
24397pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24398    match severity {
24399        lsp::DiagnosticSeverity::ERROR => colors.error,
24400        lsp::DiagnosticSeverity::WARNING => colors.warning,
24401        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24402        lsp::DiagnosticSeverity::HINT => colors.info,
24403        _ => colors.ignored,
24404    }
24405}
24406
24407pub fn styled_runs_for_code_label<'a>(
24408    label: &'a CodeLabel,
24409    syntax_theme: &'a theme::SyntaxTheme,
24410) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24411    let fade_out = HighlightStyle {
24412        fade_out: Some(0.35),
24413        ..Default::default()
24414    };
24415
24416    let mut prev_end = label.filter_range.end;
24417    label
24418        .runs
24419        .iter()
24420        .enumerate()
24421        .flat_map(move |(ix, (range, highlight_id))| {
24422            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24423                style
24424            } else {
24425                return Default::default();
24426            };
24427            let muted_style = style.highlight(fade_out);
24428
24429            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24430            if range.start >= label.filter_range.end {
24431                if range.start > prev_end {
24432                    runs.push((prev_end..range.start, fade_out));
24433                }
24434                runs.push((range.clone(), muted_style));
24435            } else if range.end <= label.filter_range.end {
24436                runs.push((range.clone(), style));
24437            } else {
24438                runs.push((range.start..label.filter_range.end, style));
24439                runs.push((label.filter_range.end..range.end, muted_style));
24440            }
24441            prev_end = cmp::max(prev_end, range.end);
24442
24443            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24444                runs.push((prev_end..label.text.len(), fade_out));
24445            }
24446
24447            runs
24448        })
24449}
24450
24451pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24452    let mut prev_index = 0;
24453    let mut prev_codepoint: Option<char> = None;
24454    text.char_indices()
24455        .chain([(text.len(), '\0')])
24456        .filter_map(move |(index, codepoint)| {
24457            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24458            let is_boundary = index == text.len()
24459                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24460                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24461            if is_boundary {
24462                let chunk = &text[prev_index..index];
24463                prev_index = index;
24464                Some(chunk)
24465            } else {
24466                None
24467            }
24468        })
24469}
24470
24471pub trait RangeToAnchorExt: Sized {
24472    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24473
24474    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24475        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24476        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24477    }
24478}
24479
24480impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24481    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24482        let start_offset = self.start.to_offset(snapshot);
24483        let end_offset = self.end.to_offset(snapshot);
24484        if start_offset == end_offset {
24485            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24486        } else {
24487            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24488        }
24489    }
24490}
24491
24492pub trait RowExt {
24493    fn as_f64(&self) -> f64;
24494
24495    fn next_row(&self) -> Self;
24496
24497    fn previous_row(&self) -> Self;
24498
24499    fn minus(&self, other: Self) -> u32;
24500}
24501
24502impl RowExt for DisplayRow {
24503    fn as_f64(&self) -> f64 {
24504        self.0 as _
24505    }
24506
24507    fn next_row(&self) -> Self {
24508        Self(self.0 + 1)
24509    }
24510
24511    fn previous_row(&self) -> Self {
24512        Self(self.0.saturating_sub(1))
24513    }
24514
24515    fn minus(&self, other: Self) -> u32 {
24516        self.0 - other.0
24517    }
24518}
24519
24520impl RowExt for MultiBufferRow {
24521    fn as_f64(&self) -> f64 {
24522        self.0 as _
24523    }
24524
24525    fn next_row(&self) -> Self {
24526        Self(self.0 + 1)
24527    }
24528
24529    fn previous_row(&self) -> Self {
24530        Self(self.0.saturating_sub(1))
24531    }
24532
24533    fn minus(&self, other: Self) -> u32 {
24534        self.0 - other.0
24535    }
24536}
24537
24538trait RowRangeExt {
24539    type Row;
24540
24541    fn len(&self) -> usize;
24542
24543    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24544}
24545
24546impl RowRangeExt for Range<MultiBufferRow> {
24547    type Row = MultiBufferRow;
24548
24549    fn len(&self) -> usize {
24550        (self.end.0 - self.start.0) as usize
24551    }
24552
24553    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24554        (self.start.0..self.end.0).map(MultiBufferRow)
24555    }
24556}
24557
24558impl RowRangeExt for Range<DisplayRow> {
24559    type Row = DisplayRow;
24560
24561    fn len(&self) -> usize {
24562        (self.end.0 - self.start.0) as usize
24563    }
24564
24565    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24566        (self.start.0..self.end.0).map(DisplayRow)
24567    }
24568}
24569
24570/// If select range has more than one line, we
24571/// just point the cursor to range.start.
24572fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24573    if range.start.row == range.end.row {
24574        range
24575    } else {
24576        range.start..range.start
24577    }
24578}
24579pub struct KillRing(ClipboardItem);
24580impl Global for KillRing {}
24581
24582const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24583
24584enum BreakpointPromptEditAction {
24585    Log,
24586    Condition,
24587    HitCondition,
24588}
24589
24590struct BreakpointPromptEditor {
24591    pub(crate) prompt: Entity<Editor>,
24592    editor: WeakEntity<Editor>,
24593    breakpoint_anchor: Anchor,
24594    breakpoint: Breakpoint,
24595    edit_action: BreakpointPromptEditAction,
24596    block_ids: HashSet<CustomBlockId>,
24597    editor_margins: Arc<Mutex<EditorMargins>>,
24598    _subscriptions: Vec<Subscription>,
24599}
24600
24601impl BreakpointPromptEditor {
24602    const MAX_LINES: u8 = 4;
24603
24604    fn new(
24605        editor: WeakEntity<Editor>,
24606        breakpoint_anchor: Anchor,
24607        breakpoint: Breakpoint,
24608        edit_action: BreakpointPromptEditAction,
24609        window: &mut Window,
24610        cx: &mut Context<Self>,
24611    ) -> Self {
24612        let base_text = match edit_action {
24613            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24614            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24615            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24616        }
24617        .map(|msg| msg.to_string())
24618        .unwrap_or_default();
24619
24620        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24621        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24622
24623        let prompt = cx.new(|cx| {
24624            let mut prompt = Editor::new(
24625                EditorMode::AutoHeight {
24626                    min_lines: 1,
24627                    max_lines: Some(Self::MAX_LINES as usize),
24628                },
24629                buffer,
24630                None,
24631                window,
24632                cx,
24633            );
24634            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24635            prompt.set_show_cursor_when_unfocused(false, cx);
24636            prompt.set_placeholder_text(
24637                match edit_action {
24638                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24639                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24640                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24641                },
24642                window,
24643                cx,
24644            );
24645
24646            prompt
24647        });
24648
24649        Self {
24650            prompt,
24651            editor,
24652            breakpoint_anchor,
24653            breakpoint,
24654            edit_action,
24655            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24656            block_ids: Default::default(),
24657            _subscriptions: vec![],
24658        }
24659    }
24660
24661    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24662        self.block_ids.extend(block_ids)
24663    }
24664
24665    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24666        if let Some(editor) = self.editor.upgrade() {
24667            let message = self
24668                .prompt
24669                .read(cx)
24670                .buffer
24671                .read(cx)
24672                .as_singleton()
24673                .expect("A multi buffer in breakpoint prompt isn't possible")
24674                .read(cx)
24675                .as_rope()
24676                .to_string();
24677
24678            editor.update(cx, |editor, cx| {
24679                editor.edit_breakpoint_at_anchor(
24680                    self.breakpoint_anchor,
24681                    self.breakpoint.clone(),
24682                    match self.edit_action {
24683                        BreakpointPromptEditAction::Log => {
24684                            BreakpointEditAction::EditLogMessage(message.into())
24685                        }
24686                        BreakpointPromptEditAction::Condition => {
24687                            BreakpointEditAction::EditCondition(message.into())
24688                        }
24689                        BreakpointPromptEditAction::HitCondition => {
24690                            BreakpointEditAction::EditHitCondition(message.into())
24691                        }
24692                    },
24693                    cx,
24694                );
24695
24696                editor.remove_blocks(self.block_ids.clone(), None, cx);
24697                cx.focus_self(window);
24698            });
24699        }
24700    }
24701
24702    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24703        self.editor
24704            .update(cx, |editor, cx| {
24705                editor.remove_blocks(self.block_ids.clone(), None, cx);
24706                window.focus(&editor.focus_handle);
24707            })
24708            .log_err();
24709    }
24710
24711    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24712        let settings = ThemeSettings::get_global(cx);
24713        let text_style = TextStyle {
24714            color: if self.prompt.read(cx).read_only(cx) {
24715                cx.theme().colors().text_disabled
24716            } else {
24717                cx.theme().colors().text
24718            },
24719            font_family: settings.buffer_font.family.clone(),
24720            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24721            font_size: settings.buffer_font_size(cx).into(),
24722            font_weight: settings.buffer_font.weight,
24723            line_height: relative(settings.buffer_line_height.value()),
24724            ..Default::default()
24725        };
24726        EditorElement::new(
24727            &self.prompt,
24728            EditorStyle {
24729                background: cx.theme().colors().editor_background,
24730                local_player: cx.theme().players().local(),
24731                text: text_style,
24732                ..Default::default()
24733            },
24734        )
24735    }
24736}
24737
24738impl Render for BreakpointPromptEditor {
24739    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24740        let editor_margins = *self.editor_margins.lock();
24741        let gutter_dimensions = editor_margins.gutter;
24742        h_flex()
24743            .key_context("Editor")
24744            .bg(cx.theme().colors().editor_background)
24745            .border_y_1()
24746            .border_color(cx.theme().status().info_border)
24747            .size_full()
24748            .py(window.line_height() / 2.5)
24749            .on_action(cx.listener(Self::confirm))
24750            .on_action(cx.listener(Self::cancel))
24751            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24752            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24753    }
24754}
24755
24756impl Focusable for BreakpointPromptEditor {
24757    fn focus_handle(&self, cx: &App) -> FocusHandle {
24758        self.prompt.focus_handle(cx)
24759    }
24760}
24761
24762fn all_edits_insertions_or_deletions(
24763    edits: &Vec<(Range<Anchor>, String)>,
24764    snapshot: &MultiBufferSnapshot,
24765) -> bool {
24766    let mut all_insertions = true;
24767    let mut all_deletions = true;
24768
24769    for (range, new_text) in edits.iter() {
24770        let range_is_empty = range.to_offset(snapshot).is_empty();
24771        let text_is_empty = new_text.is_empty();
24772
24773        if range_is_empty != text_is_empty {
24774            if range_is_empty {
24775                all_deletions = false;
24776            } else {
24777                all_insertions = false;
24778            }
24779        } else {
24780            return false;
24781        }
24782
24783        if !all_insertions && !all_deletions {
24784            return false;
24785        }
24786    }
24787    all_insertions || all_deletions
24788}
24789
24790struct MissingEditPredictionKeybindingTooltip;
24791
24792impl Render for MissingEditPredictionKeybindingTooltip {
24793    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24794        ui::tooltip_container(cx, |container, cx| {
24795            container
24796                .flex_shrink_0()
24797                .max_w_80()
24798                .min_h(rems_from_px(124.))
24799                .justify_between()
24800                .child(
24801                    v_flex()
24802                        .flex_1()
24803                        .text_ui_sm(cx)
24804                        .child(Label::new("Conflict with Accept Keybinding"))
24805                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24806                )
24807                .child(
24808                    h_flex()
24809                        .pb_1()
24810                        .gap_1()
24811                        .items_end()
24812                        .w_full()
24813                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24814                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24815                        }))
24816                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24817                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24818                        })),
24819                )
24820        })
24821    }
24822}
24823
24824#[derive(Debug, Clone, Copy, PartialEq)]
24825pub struct LineHighlight {
24826    pub background: Background,
24827    pub border: Option<gpui::Hsla>,
24828    pub include_gutter: bool,
24829    pub type_id: Option<TypeId>,
24830}
24831
24832struct LineManipulationResult {
24833    pub new_text: String,
24834    pub line_count_before: usize,
24835    pub line_count_after: usize,
24836}
24837
24838fn render_diff_hunk_controls(
24839    row: u32,
24840    status: &DiffHunkStatus,
24841    hunk_range: Range<Anchor>,
24842    is_created_file: bool,
24843    line_height: Pixels,
24844    editor: &Entity<Editor>,
24845    _window: &mut Window,
24846    cx: &mut App,
24847) -> AnyElement {
24848    h_flex()
24849        .h(line_height)
24850        .mr_1()
24851        .gap_1()
24852        .px_0p5()
24853        .pb_1()
24854        .border_x_1()
24855        .border_b_1()
24856        .border_color(cx.theme().colors().border_variant)
24857        .rounded_b_lg()
24858        .bg(cx.theme().colors().editor_background)
24859        .gap_1()
24860        .block_mouse_except_scroll()
24861        .shadow_md()
24862        .child(if status.has_secondary_hunk() {
24863            Button::new(("stage", row as u64), "Stage")
24864                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24865                .tooltip({
24866                    let focus_handle = editor.focus_handle(cx);
24867                    move |window, cx| {
24868                        Tooltip::for_action_in(
24869                            "Stage Hunk",
24870                            &::git::ToggleStaged,
24871                            &focus_handle,
24872                            window,
24873                            cx,
24874                        )
24875                    }
24876                })
24877                .on_click({
24878                    let editor = editor.clone();
24879                    move |_event, _window, cx| {
24880                        editor.update(cx, |editor, cx| {
24881                            editor.stage_or_unstage_diff_hunks(
24882                                true,
24883                                vec![hunk_range.start..hunk_range.start],
24884                                cx,
24885                            );
24886                        });
24887                    }
24888                })
24889        } else {
24890            Button::new(("unstage", row as u64), "Unstage")
24891                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24892                .tooltip({
24893                    let focus_handle = editor.focus_handle(cx);
24894                    move |window, cx| {
24895                        Tooltip::for_action_in(
24896                            "Unstage Hunk",
24897                            &::git::ToggleStaged,
24898                            &focus_handle,
24899                            window,
24900                            cx,
24901                        )
24902                    }
24903                })
24904                .on_click({
24905                    let editor = editor.clone();
24906                    move |_event, _window, cx| {
24907                        editor.update(cx, |editor, cx| {
24908                            editor.stage_or_unstage_diff_hunks(
24909                                false,
24910                                vec![hunk_range.start..hunk_range.start],
24911                                cx,
24912                            );
24913                        });
24914                    }
24915                })
24916        })
24917        .child(
24918            Button::new(("restore", row as u64), "Restore")
24919                .tooltip({
24920                    let focus_handle = editor.focus_handle(cx);
24921                    move |window, cx| {
24922                        Tooltip::for_action_in(
24923                            "Restore Hunk",
24924                            &::git::Restore,
24925                            &focus_handle,
24926                            window,
24927                            cx,
24928                        )
24929                    }
24930                })
24931                .on_click({
24932                    let editor = editor.clone();
24933                    move |_event, window, cx| {
24934                        editor.update(cx, |editor, cx| {
24935                            let snapshot = editor.snapshot(window, cx);
24936                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24937                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24938                        });
24939                    }
24940                })
24941                .disabled(is_created_file),
24942        )
24943        .when(
24944            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24945            |el| {
24946                el.child(
24947                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24948                        .shape(IconButtonShape::Square)
24949                        .icon_size(IconSize::Small)
24950                        // .disabled(!has_multiple_hunks)
24951                        .tooltip({
24952                            let focus_handle = editor.focus_handle(cx);
24953                            move |window, cx| {
24954                                Tooltip::for_action_in(
24955                                    "Next Hunk",
24956                                    &GoToHunk,
24957                                    &focus_handle,
24958                                    window,
24959                                    cx,
24960                                )
24961                            }
24962                        })
24963                        .on_click({
24964                            let editor = editor.clone();
24965                            move |_event, window, cx| {
24966                                editor.update(cx, |editor, cx| {
24967                                    let snapshot = editor.snapshot(window, cx);
24968                                    let position =
24969                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24970                                    editor.go_to_hunk_before_or_after_position(
24971                                        &snapshot,
24972                                        position,
24973                                        Direction::Next,
24974                                        window,
24975                                        cx,
24976                                    );
24977                                    editor.expand_selected_diff_hunks(cx);
24978                                });
24979                            }
24980                        }),
24981                )
24982                .child(
24983                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24984                        .shape(IconButtonShape::Square)
24985                        .icon_size(IconSize::Small)
24986                        // .disabled(!has_multiple_hunks)
24987                        .tooltip({
24988                            let focus_handle = editor.focus_handle(cx);
24989                            move |window, cx| {
24990                                Tooltip::for_action_in(
24991                                    "Previous Hunk",
24992                                    &GoToPreviousHunk,
24993                                    &focus_handle,
24994                                    window,
24995                                    cx,
24996                                )
24997                            }
24998                        })
24999                        .on_click({
25000                            let editor = editor.clone();
25001                            move |_event, window, cx| {
25002                                editor.update(cx, |editor, cx| {
25003                                    let snapshot = editor.snapshot(window, cx);
25004                                    let point =
25005                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25006                                    editor.go_to_hunk_before_or_after_position(
25007                                        &snapshot,
25008                                        point,
25009                                        Direction::Prev,
25010                                        window,
25011                                        cx,
25012                                    );
25013                                    editor.expand_selected_diff_hunks(cx);
25014                                });
25015                            }
25016                        }),
25017                )
25018            },
25019        )
25020        .into_any_element()
25021}
25022
25023pub fn multibuffer_context_lines(cx: &App) -> u32 {
25024    EditorSettings::try_get(cx)
25025        .map(|settings| settings.excerpt_context_lines)
25026        .unwrap_or(2)
25027        .min(32)
25028}