editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::{AGENT_REPLICA_ID, ReplicaId};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  150    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  151    ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  742type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  743
  744#[derive(Default)]
  745struct ScrollbarMarkerState {
  746    scrollbar_size: Size<Pixels>,
  747    dirty: bool,
  748    markers: Arc<[PaintQuad]>,
  749    pending_refresh: Option<Task<Result<()>>>,
  750}
  751
  752impl ScrollbarMarkerState {
  753    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  754        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  755    }
  756}
  757
  758#[derive(Clone, Copy, PartialEq, Eq)]
  759pub enum MinimapVisibility {
  760    Disabled,
  761    Enabled {
  762        /// The configuration currently present in the users settings.
  763        setting_configuration: bool,
  764        /// Whether to override the currently set visibility from the users setting.
  765        toggle_override: bool,
  766    },
  767}
  768
  769impl MinimapVisibility {
  770    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  771        if mode.is_full() {
  772            Self::Enabled {
  773                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  774                toggle_override: false,
  775            }
  776        } else {
  777            Self::Disabled
  778        }
  779    }
  780
  781    fn hidden(&self) -> Self {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => Self::Enabled {
  787                setting_configuration,
  788                toggle_override: setting_configuration,
  789            },
  790            Self::Disabled => Self::Disabled,
  791        }
  792    }
  793
  794    fn disabled(&self) -> bool {
  795        matches!(*self, Self::Disabled)
  796    }
  797
  798    fn settings_visibility(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                ..
  803            } => setting_configuration,
  804            _ => false,
  805        }
  806    }
  807
  808    fn visible(&self) -> bool {
  809        match *self {
  810            Self::Enabled {
  811                setting_configuration,
  812                toggle_override,
  813            } => setting_configuration ^ toggle_override,
  814            _ => false,
  815        }
  816    }
  817
  818    fn toggle_visibility(&self) -> Self {
  819        match *self {
  820            Self::Enabled {
  821                toggle_override,
  822                setting_configuration,
  823            } => Self::Enabled {
  824                setting_configuration,
  825                toggle_override: !toggle_override,
  826            },
  827            Self::Disabled => Self::Disabled,
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  864struct BufferOffset(usize);
  865
  866/// Addons allow storing per-editor state in other crates (e.g. Vim)
  867pub trait Addon: 'static {
  868    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  869
  870    fn render_buffer_header_controls(
  871        &self,
  872        _: &ExcerptInfo,
  873        _: &Window,
  874        _: &App,
  875    ) -> Option<AnyElement> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    collapse_matches: bool,
 1103    autoindent_mode: Option<AutoindentMode>,
 1104    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1105    input_enabled: bool,
 1106    use_modal_editing: bool,
 1107    read_only: bool,
 1108    leader_id: Option<CollaboratorId>,
 1109    remote_id: Option<ViewId>,
 1110    pub hover_state: HoverState,
 1111    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1112    gutter_hovered: bool,
 1113    hovered_link_state: Option<HoveredLinkState>,
 1114    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1115    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1116    active_edit_prediction: Option<EditPredictionState>,
 1117    /// Used to prevent flickering as the user types while the menu is open
 1118    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1119    edit_prediction_settings: EditPredictionSettings,
 1120    edit_predictions_hidden_for_vim_mode: bool,
 1121    show_edit_predictions_override: Option<bool>,
 1122    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1123    edit_prediction_preview: EditPredictionPreview,
 1124    edit_prediction_indent_conflict: bool,
 1125    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1126    inlay_hint_cache: InlayHintCache,
 1127    next_inlay_id: u32,
 1128    next_color_inlay_id: u32,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    serialize_dirty_buffers: bool,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191    selection_drag_state: SelectionDragState,
 1192    colors: Option<LspColorData>,
 1193    post_scroll_update: Task<()>,
 1194    refresh_colors_task: Task<()>,
 1195    folding_newlines: Task<()>,
 1196    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1197}
 1198
 1199#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1200enum NextScrollCursorCenterTopBottom {
 1201    #[default]
 1202    Center,
 1203    Top,
 1204    Bottom,
 1205}
 1206
 1207impl NextScrollCursorCenterTopBottom {
 1208    fn next(&self) -> Self {
 1209        match self {
 1210            Self::Center => Self::Top,
 1211            Self::Top => Self::Bottom,
 1212            Self::Bottom => Self::Center,
 1213        }
 1214    }
 1215}
 1216
 1217#[derive(Clone)]
 1218pub struct EditorSnapshot {
 1219    pub mode: EditorMode,
 1220    show_gutter: bool,
 1221    show_line_numbers: Option<bool>,
 1222    show_git_diff_gutter: Option<bool>,
 1223    show_code_actions: Option<bool>,
 1224    show_runnables: Option<bool>,
 1225    show_breakpoints: Option<bool>,
 1226    git_blame_gutter_max_author_length: Option<usize>,
 1227    pub display_snapshot: DisplaySnapshot,
 1228    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1229    is_focused: bool,
 1230    scroll_anchor: ScrollAnchor,
 1231    ongoing_scroll: OngoingScroll,
 1232    current_line_highlight: CurrentLineHighlight,
 1233    gutter_hovered: bool,
 1234}
 1235
 1236#[derive(Default, Debug, Clone, Copy)]
 1237pub struct GutterDimensions {
 1238    pub left_padding: Pixels,
 1239    pub right_padding: Pixels,
 1240    pub width: Pixels,
 1241    pub margin: Pixels,
 1242    pub git_blame_entries_width: Option<Pixels>,
 1243}
 1244
 1245impl GutterDimensions {
 1246    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1247        Self {
 1248            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1249            ..Default::default()
 1250        }
 1251    }
 1252
 1253    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1254        -cx.text_system().descent(font_id, font_size)
 1255    }
 1256    /// The full width of the space taken up by the gutter.
 1257    pub fn full_width(&self) -> Pixels {
 1258        self.margin + self.width
 1259    }
 1260
 1261    /// The width of the space reserved for the fold indicators,
 1262    /// use alongside 'justify_end' and `gutter_width` to
 1263    /// right align content with the line numbers
 1264    pub fn fold_area_width(&self) -> Pixels {
 1265        self.margin + self.right_padding
 1266    }
 1267}
 1268
 1269struct CharacterDimensions {
 1270    em_width: Pixels,
 1271    em_advance: Pixels,
 1272    line_height: Pixels,
 1273}
 1274
 1275#[derive(Debug)]
 1276pub struct RemoteSelection {
 1277    pub replica_id: ReplicaId,
 1278    pub selection: Selection<Anchor>,
 1279    pub cursor_shape: CursorShape,
 1280    pub collaborator_id: CollaboratorId,
 1281    pub line_mode: bool,
 1282    pub user_name: Option<SharedString>,
 1283    pub color: PlayerColor,
 1284}
 1285
 1286#[derive(Clone, Debug)]
 1287struct SelectionHistoryEntry {
 1288    selections: Arc<[Selection<Anchor>]>,
 1289    select_next_state: Option<SelectNextState>,
 1290    select_prev_state: Option<SelectNextState>,
 1291    add_selections_state: Option<AddSelectionsState>,
 1292}
 1293
 1294#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1295enum SelectionHistoryMode {
 1296    Normal,
 1297    Undoing,
 1298    Redoing,
 1299    Skipping,
 1300}
 1301
 1302#[derive(Clone, PartialEq, Eq, Hash)]
 1303struct HoveredCursor {
 1304    replica_id: u16,
 1305    selection_id: usize,
 1306}
 1307
 1308impl Default for SelectionHistoryMode {
 1309    fn default() -> Self {
 1310        Self::Normal
 1311    }
 1312}
 1313
 1314#[derive(Debug)]
 1315/// SelectionEffects controls the side-effects of updating the selection.
 1316///
 1317/// The default behaviour does "what you mostly want":
 1318/// - it pushes to the nav history if the cursor moved by >10 lines
 1319/// - it re-triggers completion requests
 1320/// - it scrolls to fit
 1321///
 1322/// You might want to modify these behaviours. For example when doing a "jump"
 1323/// like go to definition, we always want to add to nav history; but when scrolling
 1324/// in vim mode we never do.
 1325///
 1326/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1327/// move.
 1328#[derive(Clone)]
 1329pub struct SelectionEffects {
 1330    nav_history: Option<bool>,
 1331    completions: bool,
 1332    scroll: Option<Autoscroll>,
 1333}
 1334
 1335impl Default for SelectionEffects {
 1336    fn default() -> Self {
 1337        Self {
 1338            nav_history: None,
 1339            completions: true,
 1340            scroll: Some(Autoscroll::fit()),
 1341        }
 1342    }
 1343}
 1344impl SelectionEffects {
 1345    pub fn scroll(scroll: Autoscroll) -> Self {
 1346        Self {
 1347            scroll: Some(scroll),
 1348            ..Default::default()
 1349        }
 1350    }
 1351
 1352    pub fn no_scroll() -> Self {
 1353        Self {
 1354            scroll: None,
 1355            ..Default::default()
 1356        }
 1357    }
 1358
 1359    pub fn completions(self, completions: bool) -> Self {
 1360        Self {
 1361            completions,
 1362            ..self
 1363        }
 1364    }
 1365
 1366    pub fn nav_history(self, nav_history: bool) -> Self {
 1367        Self {
 1368            nav_history: Some(nav_history),
 1369            ..self
 1370        }
 1371    }
 1372}
 1373
 1374struct DeferredSelectionEffectsState {
 1375    changed: bool,
 1376    effects: SelectionEffects,
 1377    old_cursor_position: Anchor,
 1378    history_entry: SelectionHistoryEntry,
 1379}
 1380
 1381#[derive(Default)]
 1382struct SelectionHistory {
 1383    #[allow(clippy::type_complexity)]
 1384    selections_by_transaction:
 1385        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1386    mode: SelectionHistoryMode,
 1387    undo_stack: VecDeque<SelectionHistoryEntry>,
 1388    redo_stack: VecDeque<SelectionHistoryEntry>,
 1389}
 1390
 1391impl SelectionHistory {
 1392    #[track_caller]
 1393    fn insert_transaction(
 1394        &mut self,
 1395        transaction_id: TransactionId,
 1396        selections: Arc<[Selection<Anchor>]>,
 1397    ) {
 1398        if selections.is_empty() {
 1399            log::error!(
 1400                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1401                std::panic::Location::caller()
 1402            );
 1403            return;
 1404        }
 1405        self.selections_by_transaction
 1406            .insert(transaction_id, (selections, None));
 1407    }
 1408
 1409    #[allow(clippy::type_complexity)]
 1410    fn transaction(
 1411        &self,
 1412        transaction_id: TransactionId,
 1413    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1414        self.selections_by_transaction.get(&transaction_id)
 1415    }
 1416
 1417    #[allow(clippy::type_complexity)]
 1418    fn transaction_mut(
 1419        &mut self,
 1420        transaction_id: TransactionId,
 1421    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1422        self.selections_by_transaction.get_mut(&transaction_id)
 1423    }
 1424
 1425    fn push(&mut self, entry: SelectionHistoryEntry) {
 1426        if !entry.selections.is_empty() {
 1427            match self.mode {
 1428                SelectionHistoryMode::Normal => {
 1429                    self.push_undo(entry);
 1430                    self.redo_stack.clear();
 1431                }
 1432                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1433                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1434                SelectionHistoryMode::Skipping => {}
 1435            }
 1436        }
 1437    }
 1438
 1439    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1440        if self
 1441            .undo_stack
 1442            .back()
 1443            .is_none_or(|e| e.selections != entry.selections)
 1444        {
 1445            self.undo_stack.push_back(entry);
 1446            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1447                self.undo_stack.pop_front();
 1448            }
 1449        }
 1450    }
 1451
 1452    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1453        if self
 1454            .redo_stack
 1455            .back()
 1456            .is_none_or(|e| e.selections != entry.selections)
 1457        {
 1458            self.redo_stack.push_back(entry);
 1459            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1460                self.redo_stack.pop_front();
 1461            }
 1462        }
 1463    }
 1464}
 1465
 1466#[derive(Clone, Copy)]
 1467pub struct RowHighlightOptions {
 1468    pub autoscroll: bool,
 1469    pub include_gutter: bool,
 1470}
 1471
 1472impl Default for RowHighlightOptions {
 1473    fn default() -> Self {
 1474        Self {
 1475            autoscroll: Default::default(),
 1476            include_gutter: true,
 1477        }
 1478    }
 1479}
 1480
 1481struct RowHighlight {
 1482    index: usize,
 1483    range: Range<Anchor>,
 1484    color: Hsla,
 1485    options: RowHighlightOptions,
 1486    type_id: TypeId,
 1487}
 1488
 1489#[derive(Clone, Debug)]
 1490struct AddSelectionsState {
 1491    groups: Vec<AddSelectionsGroup>,
 1492}
 1493
 1494#[derive(Clone, Debug)]
 1495struct AddSelectionsGroup {
 1496    above: bool,
 1497    stack: Vec<usize>,
 1498}
 1499
 1500#[derive(Clone)]
 1501struct SelectNextState {
 1502    query: AhoCorasick,
 1503    wordwise: bool,
 1504    done: bool,
 1505}
 1506
 1507impl std::fmt::Debug for SelectNextState {
 1508    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1509        f.debug_struct(std::any::type_name::<Self>())
 1510            .field("wordwise", &self.wordwise)
 1511            .field("done", &self.done)
 1512            .finish()
 1513    }
 1514}
 1515
 1516#[derive(Debug)]
 1517struct AutocloseRegion {
 1518    selection_id: usize,
 1519    range: Range<Anchor>,
 1520    pair: BracketPair,
 1521}
 1522
 1523#[derive(Debug)]
 1524struct SnippetState {
 1525    ranges: Vec<Vec<Range<Anchor>>>,
 1526    active_index: usize,
 1527    choices: Vec<Option<Vec<String>>>,
 1528}
 1529
 1530#[doc(hidden)]
 1531pub struct RenameState {
 1532    pub range: Range<Anchor>,
 1533    pub old_name: Arc<str>,
 1534    pub editor: Entity<Editor>,
 1535    block_id: CustomBlockId,
 1536}
 1537
 1538struct InvalidationStack<T>(Vec<T>);
 1539
 1540struct RegisteredEditPredictionProvider {
 1541    provider: Arc<dyn EditPredictionProviderHandle>,
 1542    _subscription: Subscription,
 1543}
 1544
 1545#[derive(Debug, PartialEq, Eq)]
 1546pub struct ActiveDiagnosticGroup {
 1547    pub active_range: Range<Anchor>,
 1548    pub active_message: String,
 1549    pub group_id: usize,
 1550    pub blocks: HashSet<CustomBlockId>,
 1551}
 1552
 1553#[derive(Debug, PartialEq, Eq)]
 1554
 1555pub(crate) enum ActiveDiagnostic {
 1556    None,
 1557    All,
 1558    Group(ActiveDiagnosticGroup),
 1559}
 1560
 1561#[derive(Serialize, Deserialize, Clone, Debug)]
 1562pub struct ClipboardSelection {
 1563    /// The number of bytes in this selection.
 1564    pub len: usize,
 1565    /// Whether this was a full-line selection.
 1566    pub is_entire_line: bool,
 1567    /// The indentation of the first line when this content was originally copied.
 1568    pub first_line_indent: u32,
 1569}
 1570
 1571// selections, scroll behavior, was newest selection reversed
 1572type SelectSyntaxNodeHistoryState = (
 1573    Box<[Selection<usize>]>,
 1574    SelectSyntaxNodeScrollBehavior,
 1575    bool,
 1576);
 1577
 1578#[derive(Default)]
 1579struct SelectSyntaxNodeHistory {
 1580    stack: Vec<SelectSyntaxNodeHistoryState>,
 1581    // disable temporarily to allow changing selections without losing the stack
 1582    pub disable_clearing: bool,
 1583}
 1584
 1585impl SelectSyntaxNodeHistory {
 1586    pub fn try_clear(&mut self) {
 1587        if !self.disable_clearing {
 1588            self.stack.clear();
 1589        }
 1590    }
 1591
 1592    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1593        self.stack.push(selection);
 1594    }
 1595
 1596    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1597        self.stack.pop()
 1598    }
 1599}
 1600
 1601enum SelectSyntaxNodeScrollBehavior {
 1602    CursorTop,
 1603    FitSelection,
 1604    CursorBottom,
 1605}
 1606
 1607#[derive(Debug)]
 1608pub(crate) struct NavigationData {
 1609    cursor_anchor: Anchor,
 1610    cursor_position: Point,
 1611    scroll_anchor: ScrollAnchor,
 1612    scroll_top_row: u32,
 1613}
 1614
 1615#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1616pub enum GotoDefinitionKind {
 1617    Symbol,
 1618    Declaration,
 1619    Type,
 1620    Implementation,
 1621}
 1622
 1623#[derive(Debug, Clone)]
 1624enum InlayHintRefreshReason {
 1625    ModifiersChanged(bool),
 1626    Toggle(bool),
 1627    SettingsChange(InlayHintSettings),
 1628    NewLinesShown,
 1629    BufferEdited(HashSet<Arc<Language>>),
 1630    RefreshRequested,
 1631    ExcerptsRemoved(Vec<ExcerptId>),
 1632}
 1633
 1634impl InlayHintRefreshReason {
 1635    fn description(&self) -> &'static str {
 1636        match self {
 1637            Self::ModifiersChanged(_) => "modifiers changed",
 1638            Self::Toggle(_) => "toggle",
 1639            Self::SettingsChange(_) => "settings change",
 1640            Self::NewLinesShown => "new lines shown",
 1641            Self::BufferEdited(_) => "buffer edited",
 1642            Self::RefreshRequested => "refresh requested",
 1643            Self::ExcerptsRemoved(_) => "excerpts removed",
 1644        }
 1645    }
 1646}
 1647
 1648pub enum FormatTarget {
 1649    Buffers(HashSet<Entity<Buffer>>),
 1650    Ranges(Vec<Range<MultiBufferPoint>>),
 1651}
 1652
 1653pub(crate) struct FocusedBlock {
 1654    id: BlockId,
 1655    focus_handle: WeakFocusHandle,
 1656}
 1657
 1658#[derive(Clone)]
 1659enum JumpData {
 1660    MultiBufferRow {
 1661        row: MultiBufferRow,
 1662        line_offset_from_top: u32,
 1663    },
 1664    MultiBufferPoint {
 1665        excerpt_id: ExcerptId,
 1666        position: Point,
 1667        anchor: text::Anchor,
 1668        line_offset_from_top: u32,
 1669    },
 1670}
 1671
 1672pub enum MultibufferSelectionMode {
 1673    First,
 1674    All,
 1675}
 1676
 1677#[derive(Clone, Copy, Debug, Default)]
 1678pub struct RewrapOptions {
 1679    pub override_language_settings: bool,
 1680    pub preserve_existing_whitespace: bool,
 1681}
 1682
 1683impl Editor {
 1684    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1688    }
 1689
 1690    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1691        let buffer = cx.new(|cx| Buffer::local("", cx));
 1692        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1693        Self::new(EditorMode::full(), buffer, None, window, cx)
 1694    }
 1695
 1696    pub fn auto_height(
 1697        min_lines: usize,
 1698        max_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: Some(max_lines),
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1717    /// The editor grows as tall as needed to fit its content.
 1718    pub fn auto_height_unbounded(
 1719        min_lines: usize,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| Buffer::local("", cx));
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(
 1726            EditorMode::AutoHeight {
 1727                min_lines,
 1728                max_lines: None,
 1729            },
 1730            buffer,
 1731            None,
 1732            window,
 1733            cx,
 1734        )
 1735    }
 1736
 1737    pub fn for_buffer(
 1738        buffer: Entity<Buffer>,
 1739        project: Option<Entity<Project>>,
 1740        window: &mut Window,
 1741        cx: &mut Context<Self>,
 1742    ) -> Self {
 1743        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1744        Self::new(EditorMode::full(), buffer, project, window, cx)
 1745    }
 1746
 1747    pub fn for_multibuffer(
 1748        buffer: Entity<MultiBuffer>,
 1749        project: Option<Entity<Project>>,
 1750        window: &mut Window,
 1751        cx: &mut Context<Self>,
 1752    ) -> Self {
 1753        Self::new(EditorMode::full(), buffer, project, window, cx)
 1754    }
 1755
 1756    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1757        let mut clone = Self::new(
 1758            self.mode.clone(),
 1759            self.buffer.clone(),
 1760            self.project.clone(),
 1761            window,
 1762            cx,
 1763        );
 1764        self.display_map.update(cx, |display_map, cx| {
 1765            let snapshot = display_map.snapshot(cx);
 1766            clone.display_map.update(cx, |display_map, cx| {
 1767                display_map.set_state(&snapshot, cx);
 1768            });
 1769        });
 1770        clone.folds_did_change(cx);
 1771        clone.selections.clone_state(&self.selections);
 1772        clone.scroll_manager.clone_state(&self.scroll_manager);
 1773        clone.searchable = self.searchable;
 1774        clone.read_only = self.read_only;
 1775        clone
 1776    }
 1777
 1778    pub fn new(
 1779        mode: EditorMode,
 1780        buffer: Entity<MultiBuffer>,
 1781        project: Option<Entity<Project>>,
 1782        window: &mut Window,
 1783        cx: &mut Context<Self>,
 1784    ) -> Self {
 1785        Editor::new_internal(mode, buffer, project, None, window, cx)
 1786    }
 1787
 1788    fn new_internal(
 1789        mode: EditorMode,
 1790        multi_buffer: Entity<MultiBuffer>,
 1791        project: Option<Entity<Project>>,
 1792        display_map: Option<Entity<DisplayMap>>,
 1793        window: &mut Window,
 1794        cx: &mut Context<Self>,
 1795    ) -> Self {
 1796        debug_assert!(
 1797            display_map.is_none() || mode.is_minimap(),
 1798            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1799        );
 1800
 1801        let full_mode = mode.is_full();
 1802        let is_minimap = mode.is_minimap();
 1803        let diagnostics_max_severity = if full_mode {
 1804            EditorSettings::get_global(cx)
 1805                .diagnostics_max_severity
 1806                .unwrap_or(DiagnosticSeverity::Hint)
 1807        } else {
 1808            DiagnosticSeverity::Off
 1809        };
 1810        let style = window.text_style();
 1811        let font_size = style.font_size.to_pixels(window.rem_size());
 1812        let editor = cx.entity().downgrade();
 1813        let fold_placeholder = FoldPlaceholder {
 1814            constrain_width: false,
 1815            render: Arc::new(move |fold_id, fold_range, cx| {
 1816                let editor = editor.clone();
 1817                div()
 1818                    .id(fold_id)
 1819                    .bg(cx.theme().colors().ghost_element_background)
 1820                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1821                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1822                    .rounded_xs()
 1823                    .size_full()
 1824                    .cursor_pointer()
 1825                    .child("")
 1826                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1827                    .on_click(move |_, _window, cx| {
 1828                        editor
 1829                            .update(cx, |editor, cx| {
 1830                                editor.unfold_ranges(
 1831                                    &[fold_range.start..fold_range.end],
 1832                                    true,
 1833                                    false,
 1834                                    cx,
 1835                                );
 1836                                cx.stop_propagation();
 1837                            })
 1838                            .ok();
 1839                    })
 1840                    .into_any()
 1841            }),
 1842            merge_adjacent: true,
 1843            ..FoldPlaceholder::default()
 1844        };
 1845        let display_map = display_map.unwrap_or_else(|| {
 1846            cx.new(|cx| {
 1847                DisplayMap::new(
 1848                    multi_buffer.clone(),
 1849                    style.font(),
 1850                    font_size,
 1851                    None,
 1852                    FILE_HEADER_HEIGHT,
 1853                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1854                    fold_placeholder,
 1855                    diagnostics_max_severity,
 1856                    cx,
 1857                )
 1858            })
 1859        });
 1860
 1861        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1862
 1863        let blink_manager = cx.new(|cx| {
 1864            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1865            if is_minimap {
 1866                blink_manager.disable(cx);
 1867            }
 1868            blink_manager
 1869        });
 1870
 1871        let soft_wrap_mode_override =
 1872            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1873
 1874        let mut project_subscriptions = Vec::new();
 1875        if full_mode && let Some(project) = project.as_ref() {
 1876            project_subscriptions.push(cx.subscribe_in(
 1877                project,
 1878                window,
 1879                |editor, _, event, window, cx| match event {
 1880                    project::Event::RefreshCodeLens => {
 1881                        // we always query lens with actions, without storing them, always refreshing them
 1882                    }
 1883                    project::Event::RefreshInlayHints => {
 1884                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1885                    }
 1886                    project::Event::LanguageServerRemoved(..) => {
 1887                        if editor.tasks_update_task.is_none() {
 1888                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1889                        }
 1890                        editor.registered_buffers.clear();
 1891                        editor.register_visible_buffers(cx);
 1892                    }
 1893                    project::Event::LanguageServerAdded(..) => {
 1894                        if editor.tasks_update_task.is_none() {
 1895                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1896                        }
 1897                    }
 1898                    project::Event::SnippetEdit(id, snippet_edits) => {
 1899                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1900                            let focus_handle = editor.focus_handle(cx);
 1901                            if focus_handle.is_focused(window) {
 1902                                let snapshot = buffer.read(cx).snapshot();
 1903                                for (range, snippet) in snippet_edits {
 1904                                    let editor_range =
 1905                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1906                                    editor
 1907                                        .insert_snippet(
 1908                                            &[editor_range],
 1909                                            snippet.clone(),
 1910                                            window,
 1911                                            cx,
 1912                                        )
 1913                                        .ok();
 1914                                }
 1915                            }
 1916                        }
 1917                    }
 1918                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1919                        let buffer_id = *buffer_id;
 1920                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1921                            let registered = editor.register_buffer(buffer_id, cx);
 1922                            if registered {
 1923                                editor.update_lsp_data(Some(buffer_id), window, cx);
 1924                                editor.refresh_inlay_hints(
 1925                                    InlayHintRefreshReason::RefreshRequested,
 1926                                    cx,
 1927                                );
 1928                                refresh_linked_ranges(editor, window, cx);
 1929                                editor.refresh_code_actions(window, cx);
 1930                                editor.refresh_document_highlights(cx);
 1931                            }
 1932                        }
 1933                    }
 1934
 1935                    project::Event::EntryRenamed(transaction) => {
 1936                        let Some(workspace) = editor.workspace() else {
 1937                            return;
 1938                        };
 1939                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1940                        else {
 1941                            return;
 1942                        };
 1943                        if active_editor.entity_id() == cx.entity_id() {
 1944                            let edited_buffers_already_open = {
 1945                                let other_editors: Vec<Entity<Editor>> = workspace
 1946                                    .read(cx)
 1947                                    .panes()
 1948                                    .iter()
 1949                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1950                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1951                                    .collect();
 1952
 1953                                transaction.0.keys().all(|buffer| {
 1954                                    other_editors.iter().any(|editor| {
 1955                                        let multi_buffer = editor.read(cx).buffer();
 1956                                        multi_buffer.read(cx).is_singleton()
 1957                                            && multi_buffer.read(cx).as_singleton().map_or(
 1958                                                false,
 1959                                                |singleton| {
 1960                                                    singleton.entity_id() == buffer.entity_id()
 1961                                                },
 1962                                            )
 1963                                    })
 1964                                })
 1965                            };
 1966
 1967                            if !edited_buffers_already_open {
 1968                                let workspace = workspace.downgrade();
 1969                                let transaction = transaction.clone();
 1970                                cx.defer_in(window, move |_, window, cx| {
 1971                                    cx.spawn_in(window, async move |editor, cx| {
 1972                                        Self::open_project_transaction(
 1973                                            &editor,
 1974                                            workspace,
 1975                                            transaction,
 1976                                            "Rename".to_string(),
 1977                                            cx,
 1978                                        )
 1979                                        .await
 1980                                        .ok()
 1981                                    })
 1982                                    .detach();
 1983                                });
 1984                            }
 1985                        }
 1986                    }
 1987
 1988                    _ => {}
 1989                },
 1990            ));
 1991            if let Some(task_inventory) = project
 1992                .read(cx)
 1993                .task_store()
 1994                .read(cx)
 1995                .task_inventory()
 1996                .cloned()
 1997            {
 1998                project_subscriptions.push(cx.observe_in(
 1999                    &task_inventory,
 2000                    window,
 2001                    |editor, _, window, cx| {
 2002                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2003                    },
 2004                ));
 2005            };
 2006
 2007            project_subscriptions.push(cx.subscribe_in(
 2008                &project.read(cx).breakpoint_store(),
 2009                window,
 2010                |editor, _, event, window, cx| match event {
 2011                    BreakpointStoreEvent::ClearDebugLines => {
 2012                        editor.clear_row_highlights::<ActiveDebugLine>();
 2013                        editor.refresh_inline_values(cx);
 2014                    }
 2015                    BreakpointStoreEvent::SetDebugLine => {
 2016                        if editor.go_to_active_debug_line(window, cx) {
 2017                            cx.stop_propagation();
 2018                        }
 2019
 2020                        editor.refresh_inline_values(cx);
 2021                    }
 2022                    _ => {}
 2023                },
 2024            ));
 2025            let git_store = project.read(cx).git_store().clone();
 2026            let project = project.clone();
 2027            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2028                if let GitStoreEvent::RepositoryUpdated(
 2029                    _,
 2030                    RepositoryEvent::Updated {
 2031                        new_instance: true, ..
 2032                    },
 2033                    _,
 2034                ) = event
 2035                {
 2036                    this.load_diff_task = Some(
 2037                        update_uncommitted_diff_for_buffer(
 2038                            cx.entity(),
 2039                            &project,
 2040                            this.buffer.read(cx).all_buffers(),
 2041                            this.buffer.clone(),
 2042                            cx,
 2043                        )
 2044                        .shared(),
 2045                    );
 2046                }
 2047            }));
 2048        }
 2049
 2050        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2051
 2052        let inlay_hint_settings =
 2053            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2054        let focus_handle = cx.focus_handle();
 2055        if !is_minimap {
 2056            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2057                .detach();
 2058            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2059                .detach();
 2060            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2061                .detach();
 2062            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2063                .detach();
 2064            cx.observe_pending_input(window, Self::observe_pending_input)
 2065                .detach();
 2066        }
 2067
 2068        let show_indent_guides =
 2069            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2070                Some(false)
 2071            } else {
 2072                None
 2073            };
 2074
 2075        let breakpoint_store = match (&mode, project.as_ref()) {
 2076            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2077            _ => None,
 2078        };
 2079
 2080        let mut code_action_providers = Vec::new();
 2081        let mut load_uncommitted_diff = None;
 2082        if let Some(project) = project.clone() {
 2083            load_uncommitted_diff = Some(
 2084                update_uncommitted_diff_for_buffer(
 2085                    cx.entity(),
 2086                    &project,
 2087                    multi_buffer.read(cx).all_buffers(),
 2088                    multi_buffer.clone(),
 2089                    cx,
 2090                )
 2091                .shared(),
 2092            );
 2093            code_action_providers.push(Rc::new(project) as Rc<_>);
 2094        }
 2095
 2096        let mut editor = Self {
 2097            focus_handle,
 2098            show_cursor_when_unfocused: false,
 2099            last_focused_descendant: None,
 2100            buffer: multi_buffer.clone(),
 2101            display_map: display_map.clone(),
 2102            placeholder_display_map: None,
 2103            selections,
 2104            scroll_manager: ScrollManager::new(cx),
 2105            columnar_selection_state: None,
 2106            add_selections_state: None,
 2107            select_next_state: None,
 2108            select_prev_state: None,
 2109            selection_history: SelectionHistory::default(),
 2110            defer_selection_effects: false,
 2111            deferred_selection_effects_state: None,
 2112            autoclose_regions: Vec::new(),
 2113            snippet_stack: InvalidationStack::default(),
 2114            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2115            ime_transaction: None,
 2116            active_diagnostics: ActiveDiagnostic::None,
 2117            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2118            inline_diagnostics_update: Task::ready(()),
 2119            inline_diagnostics: Vec::new(),
 2120            soft_wrap_mode_override,
 2121            diagnostics_max_severity,
 2122            hard_wrap: None,
 2123            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2124            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2125            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2126            project,
 2127            blink_manager: blink_manager.clone(),
 2128            show_local_selections: true,
 2129            show_scrollbars: ScrollbarAxes {
 2130                horizontal: full_mode,
 2131                vertical: full_mode,
 2132            },
 2133            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2134            offset_content: !matches!(mode, EditorMode::SingleLine),
 2135            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2136            show_gutter: full_mode,
 2137            show_line_numbers: (!full_mode).then_some(false),
 2138            use_relative_line_numbers: None,
 2139            disable_expand_excerpt_buttons: !full_mode,
 2140            show_git_diff_gutter: None,
 2141            show_code_actions: None,
 2142            show_runnables: None,
 2143            show_breakpoints: None,
 2144            show_wrap_guides: None,
 2145            show_indent_guides,
 2146            highlight_order: 0,
 2147            highlighted_rows: HashMap::default(),
 2148            background_highlights: HashMap::default(),
 2149            gutter_highlights: HashMap::default(),
 2150            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2151            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2152            nav_history: None,
 2153            context_menu: RefCell::new(None),
 2154            context_menu_options: None,
 2155            mouse_context_menu: None,
 2156            completion_tasks: Vec::new(),
 2157            inline_blame_popover: None,
 2158            inline_blame_popover_show_task: None,
 2159            signature_help_state: SignatureHelpState::default(),
 2160            auto_signature_help: None,
 2161            find_all_references_task_sources: Vec::new(),
 2162            next_completion_id: 0,
 2163            next_inlay_id: 0,
 2164            code_action_providers,
 2165            available_code_actions: None,
 2166            code_actions_task: None,
 2167            quick_selection_highlight_task: None,
 2168            debounced_selection_highlight_task: None,
 2169            document_highlights_task: None,
 2170            linked_editing_range_task: None,
 2171            pending_rename: None,
 2172            searchable: !is_minimap,
 2173            cursor_shape: EditorSettings::get_global(cx)
 2174                .cursor_shape
 2175                .unwrap_or_default(),
 2176            current_line_highlight: None,
 2177            autoindent_mode: Some(AutoindentMode::EachLine),
 2178            collapse_matches: false,
 2179            workspace: None,
 2180            input_enabled: !is_minimap,
 2181            use_modal_editing: full_mode,
 2182            read_only: is_minimap,
 2183            use_autoclose: true,
 2184            use_auto_surround: true,
 2185            auto_replace_emoji_shortcode: false,
 2186            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2187            leader_id: None,
 2188            remote_id: None,
 2189            hover_state: HoverState::default(),
 2190            pending_mouse_down: None,
 2191            hovered_link_state: None,
 2192            edit_prediction_provider: None,
 2193            active_edit_prediction: None,
 2194            stale_edit_prediction_in_menu: None,
 2195            edit_prediction_preview: EditPredictionPreview::Inactive {
 2196                released_too_fast: false,
 2197            },
 2198            inline_diagnostics_enabled: full_mode,
 2199            diagnostics_enabled: full_mode,
 2200            word_completions_enabled: full_mode,
 2201            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2202            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2203            gutter_hovered: false,
 2204            pixel_position_of_newest_cursor: None,
 2205            last_bounds: None,
 2206            last_position_map: None,
 2207            expect_bounds_change: None,
 2208            gutter_dimensions: GutterDimensions::default(),
 2209            style: None,
 2210            show_cursor_names: false,
 2211            hovered_cursors: HashMap::default(),
 2212            next_editor_action_id: EditorActionId::default(),
 2213            editor_actions: Rc::default(),
 2214            edit_predictions_hidden_for_vim_mode: false,
 2215            show_edit_predictions_override: None,
 2216            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2217            edit_prediction_settings: EditPredictionSettings::Disabled,
 2218            edit_prediction_indent_conflict: false,
 2219            edit_prediction_requires_modifier_in_indent_conflict: true,
 2220            custom_context_menu: None,
 2221            show_git_blame_gutter: false,
 2222            show_git_blame_inline: false,
 2223            show_selection_menu: None,
 2224            show_git_blame_inline_delay_task: None,
 2225            git_blame_inline_enabled: full_mode
 2226                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2227            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2228            serialize_dirty_buffers: !is_minimap
 2229                && ProjectSettings::get_global(cx)
 2230                    .session
 2231                    .restore_unsaved_buffers,
 2232            blame: None,
 2233            blame_subscription: None,
 2234            tasks: BTreeMap::default(),
 2235
 2236            breakpoint_store,
 2237            gutter_breakpoint_indicator: (None, None),
 2238            hovered_diff_hunk_row: None,
 2239            _subscriptions: (!is_minimap)
 2240                .then(|| {
 2241                    vec![
 2242                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2243                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2244                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2245                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2246                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2247                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2248                        cx.observe_window_activation(window, |editor, window, cx| {
 2249                            let active = window.is_window_active();
 2250                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2251                                if active {
 2252                                    blink_manager.enable(cx);
 2253                                } else {
 2254                                    blink_manager.disable(cx);
 2255                                }
 2256                            });
 2257                            if active {
 2258                                editor.show_mouse_cursor(cx);
 2259                            }
 2260                        }),
 2261                    ]
 2262                })
 2263                .unwrap_or_default(),
 2264            tasks_update_task: None,
 2265            pull_diagnostics_task: Task::ready(()),
 2266            colors: None,
 2267            refresh_colors_task: Task::ready(()),
 2268            next_color_inlay_id: 0,
 2269            post_scroll_update: Task::ready(()),
 2270            linked_edit_ranges: Default::default(),
 2271            in_project_search: false,
 2272            previous_search_ranges: None,
 2273            breadcrumb_header: None,
 2274            focused_block: None,
 2275            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2276            addons: HashMap::default(),
 2277            registered_buffers: HashMap::default(),
 2278            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2279            selection_mark_mode: false,
 2280            toggle_fold_multiple_buffers: Task::ready(()),
 2281            serialize_selections: Task::ready(()),
 2282            serialize_folds: Task::ready(()),
 2283            text_style_refinement: None,
 2284            load_diff_task: load_uncommitted_diff,
 2285            temporary_diff_override: false,
 2286            mouse_cursor_hidden: false,
 2287            minimap: None,
 2288            hide_mouse_mode: EditorSettings::get_global(cx)
 2289                .hide_mouse
 2290                .unwrap_or_default(),
 2291            change_list: ChangeList::new(),
 2292            mode,
 2293            selection_drag_state: SelectionDragState::None,
 2294            folding_newlines: Task::ready(()),
 2295            lookup_key: None,
 2296        };
 2297
 2298        if is_minimap {
 2299            return editor;
 2300        }
 2301
 2302        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2303            editor
 2304                ._subscriptions
 2305                .push(cx.observe(breakpoints, |_, _, cx| {
 2306                    cx.notify();
 2307                }));
 2308        }
 2309        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2310        editor._subscriptions.extend(project_subscriptions);
 2311
 2312        editor._subscriptions.push(cx.subscribe_in(
 2313            &cx.entity(),
 2314            window,
 2315            |editor, _, e: &EditorEvent, window, cx| match e {
 2316                EditorEvent::ScrollPositionChanged { local, .. } => {
 2317                    if *local {
 2318                        let new_anchor = editor.scroll_manager.anchor();
 2319                        let snapshot = editor.snapshot(window, cx);
 2320                        editor.update_restoration_data(cx, move |data| {
 2321                            data.scroll_position = (
 2322                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2323                                new_anchor.offset,
 2324                            );
 2325                        });
 2326                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2327                        editor.inline_blame_popover.take();
 2328                    }
 2329                }
 2330                EditorEvent::Edited { .. } => {
 2331                    if !vim_enabled(cx) {
 2332                        let display_map = editor.display_snapshot(cx);
 2333                        let selections = editor.selections.all_adjusted_display(&display_map);
 2334                        let pop_state = editor
 2335                            .change_list
 2336                            .last()
 2337                            .map(|previous| {
 2338                                previous.len() == selections.len()
 2339                                    && previous.iter().enumerate().all(|(ix, p)| {
 2340                                        p.to_display_point(&display_map).row()
 2341                                            == selections[ix].head().row()
 2342                                    })
 2343                            })
 2344                            .unwrap_or(false);
 2345                        let new_positions = selections
 2346                            .into_iter()
 2347                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2348                            .collect();
 2349                        editor
 2350                            .change_list
 2351                            .push_to_change_list(pop_state, new_positions);
 2352                    }
 2353                }
 2354                _ => (),
 2355            },
 2356        ));
 2357
 2358        if let Some(dap_store) = editor
 2359            .project
 2360            .as_ref()
 2361            .map(|project| project.read(cx).dap_store())
 2362        {
 2363            let weak_editor = cx.weak_entity();
 2364
 2365            editor
 2366                ._subscriptions
 2367                .push(
 2368                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2369                        let session_entity = cx.entity();
 2370                        weak_editor
 2371                            .update(cx, |editor, cx| {
 2372                                editor._subscriptions.push(
 2373                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2374                                );
 2375                            })
 2376                            .ok();
 2377                    }),
 2378                );
 2379
 2380            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2381                editor
 2382                    ._subscriptions
 2383                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2384            }
 2385        }
 2386
 2387        // skip adding the initial selection to selection history
 2388        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2389        editor.end_selection(window, cx);
 2390        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2391
 2392        editor.scroll_manager.show_scrollbars(window, cx);
 2393        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2394
 2395        if full_mode {
 2396            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2397            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2398
 2399            if editor.git_blame_inline_enabled {
 2400                editor.start_git_blame_inline(false, window, cx);
 2401            }
 2402
 2403            editor.go_to_active_debug_line(window, cx);
 2404
 2405            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2406                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2407            }
 2408
 2409            editor.minimap =
 2410                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2411            editor.colors = Some(LspColorData::new(cx));
 2412            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2413        }
 2414
 2415        editor
 2416    }
 2417
 2418    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2419        self.selections.display_map(cx)
 2420    }
 2421
 2422    pub fn deploy_mouse_context_menu(
 2423        &mut self,
 2424        position: gpui::Point<Pixels>,
 2425        context_menu: Entity<ContextMenu>,
 2426        window: &mut Window,
 2427        cx: &mut Context<Self>,
 2428    ) {
 2429        self.mouse_context_menu = Some(MouseContextMenu::new(
 2430            self,
 2431            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2432            context_menu,
 2433            window,
 2434            cx,
 2435        ));
 2436    }
 2437
 2438    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2439        self.mouse_context_menu
 2440            .as_ref()
 2441            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2442    }
 2443
 2444    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2445        if self
 2446            .selections
 2447            .pending_anchor()
 2448            .is_some_and(|pending_selection| {
 2449                let snapshot = self.buffer().read(cx).snapshot(cx);
 2450                pending_selection.range().includes(range, &snapshot)
 2451            })
 2452        {
 2453            return true;
 2454        }
 2455
 2456        self.selections
 2457            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2458            .into_iter()
 2459            .any(|selection| {
 2460                // This is needed to cover a corner case, if we just check for an existing
 2461                // selection in the fold range, having a cursor at the start of the fold
 2462                // marks it as selected. Non-empty selections don't cause this.
 2463                let length = selection.end - selection.start;
 2464                length > 0
 2465            })
 2466    }
 2467
 2468    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2469        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2470    }
 2471
 2472    fn key_context_internal(
 2473        &self,
 2474        has_active_edit_prediction: bool,
 2475        window: &Window,
 2476        cx: &App,
 2477    ) -> KeyContext {
 2478        let mut key_context = KeyContext::new_with_defaults();
 2479        key_context.add("Editor");
 2480        let mode = match self.mode {
 2481            EditorMode::SingleLine => "single_line",
 2482            EditorMode::AutoHeight { .. } => "auto_height",
 2483            EditorMode::Minimap { .. } => "minimap",
 2484            EditorMode::Full { .. } => "full",
 2485        };
 2486
 2487        if EditorSettings::jupyter_enabled(cx) {
 2488            key_context.add("jupyter");
 2489        }
 2490
 2491        key_context.set("mode", mode);
 2492        if self.pending_rename.is_some() {
 2493            key_context.add("renaming");
 2494        }
 2495
 2496        match self.context_menu.borrow().as_ref() {
 2497            Some(CodeContextMenu::Completions(menu)) => {
 2498                if menu.visible() {
 2499                    key_context.add("menu");
 2500                    key_context.add("showing_completions");
 2501                }
 2502            }
 2503            Some(CodeContextMenu::CodeActions(menu)) => {
 2504                if menu.visible() {
 2505                    key_context.add("menu");
 2506                    key_context.add("showing_code_actions")
 2507                }
 2508            }
 2509            None => {}
 2510        }
 2511
 2512        if self.signature_help_state.has_multiple_signatures() {
 2513            key_context.add("showing_signature_help");
 2514        }
 2515
 2516        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2517        if !self.focus_handle(cx).contains_focused(window, cx)
 2518            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2519        {
 2520            for addon in self.addons.values() {
 2521                addon.extend_key_context(&mut key_context, cx)
 2522            }
 2523        }
 2524
 2525        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2526            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2527                Some(
 2528                    file.full_path(cx)
 2529                        .extension()?
 2530                        .to_string_lossy()
 2531                        .into_owned(),
 2532                )
 2533            }) {
 2534                key_context.set("extension", extension);
 2535            }
 2536        } else {
 2537            key_context.add("multibuffer");
 2538        }
 2539
 2540        if has_active_edit_prediction {
 2541            if self.edit_prediction_in_conflict() {
 2542                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2543            } else {
 2544                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2545                key_context.add("copilot_suggestion");
 2546            }
 2547        }
 2548
 2549        if self.selection_mark_mode {
 2550            key_context.add("selection_mode");
 2551        }
 2552
 2553        key_context
 2554    }
 2555
 2556    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2557        self.last_bounds.as_ref()
 2558    }
 2559
 2560    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2561        if self.mouse_cursor_hidden {
 2562            self.mouse_cursor_hidden = false;
 2563            cx.notify();
 2564        }
 2565    }
 2566
 2567    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2568        let hide_mouse_cursor = match origin {
 2569            HideMouseCursorOrigin::TypingAction => {
 2570                matches!(
 2571                    self.hide_mouse_mode,
 2572                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2573                )
 2574            }
 2575            HideMouseCursorOrigin::MovementAction => {
 2576                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2577            }
 2578        };
 2579        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2580            self.mouse_cursor_hidden = hide_mouse_cursor;
 2581            cx.notify();
 2582        }
 2583    }
 2584
 2585    pub fn edit_prediction_in_conflict(&self) -> bool {
 2586        if !self.show_edit_predictions_in_menu() {
 2587            return false;
 2588        }
 2589
 2590        let showing_completions = self
 2591            .context_menu
 2592            .borrow()
 2593            .as_ref()
 2594            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2595
 2596        showing_completions
 2597            || self.edit_prediction_requires_modifier()
 2598            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2599            // bindings to insert tab characters.
 2600            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2601    }
 2602
 2603    pub fn accept_edit_prediction_keybind(
 2604        &self,
 2605        accept_partial: bool,
 2606        window: &Window,
 2607        cx: &App,
 2608    ) -> AcceptEditPredictionBinding {
 2609        let key_context = self.key_context_internal(true, window, cx);
 2610        let in_conflict = self.edit_prediction_in_conflict();
 2611
 2612        let bindings = if accept_partial {
 2613            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2614        } else {
 2615            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2616        };
 2617
 2618        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2619        // just the first one.
 2620        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2621            !in_conflict
 2622                || binding
 2623                    .keystrokes()
 2624                    .first()
 2625                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2626        }))
 2627    }
 2628
 2629    pub fn new_file(
 2630        workspace: &mut Workspace,
 2631        _: &workspace::NewFile,
 2632        window: &mut Window,
 2633        cx: &mut Context<Workspace>,
 2634    ) {
 2635        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2636            "Failed to create buffer",
 2637            window,
 2638            cx,
 2639            |e, _, _| match e.error_code() {
 2640                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2641                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2642                e.error_tag("required").unwrap_or("the latest version")
 2643            )),
 2644                _ => None,
 2645            },
 2646        );
 2647    }
 2648
 2649    pub fn new_in_workspace(
 2650        workspace: &mut Workspace,
 2651        window: &mut Window,
 2652        cx: &mut Context<Workspace>,
 2653    ) -> Task<Result<Entity<Editor>>> {
 2654        let project = workspace.project().clone();
 2655        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2656
 2657        cx.spawn_in(window, async move |workspace, cx| {
 2658            let buffer = create.await?;
 2659            workspace.update_in(cx, |workspace, window, cx| {
 2660                let editor =
 2661                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2662                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2663                editor
 2664            })
 2665        })
 2666    }
 2667
 2668    fn new_file_vertical(
 2669        workspace: &mut Workspace,
 2670        _: &workspace::NewFileSplitVertical,
 2671        window: &mut Window,
 2672        cx: &mut Context<Workspace>,
 2673    ) {
 2674        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2675    }
 2676
 2677    fn new_file_horizontal(
 2678        workspace: &mut Workspace,
 2679        _: &workspace::NewFileSplitHorizontal,
 2680        window: &mut Window,
 2681        cx: &mut Context<Workspace>,
 2682    ) {
 2683        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2684    }
 2685
 2686    fn new_file_in_direction(
 2687        workspace: &mut Workspace,
 2688        direction: SplitDirection,
 2689        window: &mut Window,
 2690        cx: &mut Context<Workspace>,
 2691    ) {
 2692        let project = workspace.project().clone();
 2693        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2694
 2695        cx.spawn_in(window, async move |workspace, cx| {
 2696            let buffer = create.await?;
 2697            workspace.update_in(cx, move |workspace, window, cx| {
 2698                workspace.split_item(
 2699                    direction,
 2700                    Box::new(
 2701                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2702                    ),
 2703                    window,
 2704                    cx,
 2705                )
 2706            })?;
 2707            anyhow::Ok(())
 2708        })
 2709        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2710            match e.error_code() {
 2711                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2712                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2713                e.error_tag("required").unwrap_or("the latest version")
 2714            )),
 2715                _ => None,
 2716            }
 2717        });
 2718    }
 2719
 2720    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2721        self.leader_id
 2722    }
 2723
 2724    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2725        &self.buffer
 2726    }
 2727
 2728    pub fn project(&self) -> Option<&Entity<Project>> {
 2729        self.project.as_ref()
 2730    }
 2731
 2732    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2733        self.workspace.as_ref()?.0.upgrade()
 2734    }
 2735
 2736    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2737        self.buffer().read(cx).title(cx)
 2738    }
 2739
 2740    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2741        let git_blame_gutter_max_author_length = self
 2742            .render_git_blame_gutter(cx)
 2743            .then(|| {
 2744                if let Some(blame) = self.blame.as_ref() {
 2745                    let max_author_length =
 2746                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2747                    Some(max_author_length)
 2748                } else {
 2749                    None
 2750                }
 2751            })
 2752            .flatten();
 2753
 2754        EditorSnapshot {
 2755            mode: self.mode.clone(),
 2756            show_gutter: self.show_gutter,
 2757            show_line_numbers: self.show_line_numbers,
 2758            show_git_diff_gutter: self.show_git_diff_gutter,
 2759            show_code_actions: self.show_code_actions,
 2760            show_runnables: self.show_runnables,
 2761            show_breakpoints: self.show_breakpoints,
 2762            git_blame_gutter_max_author_length,
 2763            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2764            placeholder_display_snapshot: self
 2765                .placeholder_display_map
 2766                .as_ref()
 2767                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2768            scroll_anchor: self.scroll_manager.anchor(),
 2769            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2770            is_focused: self.focus_handle.is_focused(window),
 2771            current_line_highlight: self
 2772                .current_line_highlight
 2773                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2774            gutter_hovered: self.gutter_hovered,
 2775        }
 2776    }
 2777
 2778    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2779        self.buffer.read(cx).language_at(point, cx)
 2780    }
 2781
 2782    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2783        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2784    }
 2785
 2786    pub fn active_excerpt(
 2787        &self,
 2788        cx: &App,
 2789    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2790        self.buffer
 2791            .read(cx)
 2792            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2793    }
 2794
 2795    pub fn mode(&self) -> &EditorMode {
 2796        &self.mode
 2797    }
 2798
 2799    pub fn set_mode(&mut self, mode: EditorMode) {
 2800        self.mode = mode;
 2801    }
 2802
 2803    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2804        self.collaboration_hub.as_deref()
 2805    }
 2806
 2807    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2808        self.collaboration_hub = Some(hub);
 2809    }
 2810
 2811    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2812        self.in_project_search = in_project_search;
 2813    }
 2814
 2815    pub fn set_custom_context_menu(
 2816        &mut self,
 2817        f: impl 'static
 2818        + Fn(
 2819            &mut Self,
 2820            DisplayPoint,
 2821            &mut Window,
 2822            &mut Context<Self>,
 2823        ) -> Option<Entity<ui::ContextMenu>>,
 2824    ) {
 2825        self.custom_context_menu = Some(Box::new(f))
 2826    }
 2827
 2828    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2829        self.completion_provider = provider;
 2830    }
 2831
 2832    #[cfg(any(test, feature = "test-support"))]
 2833    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2834        self.completion_provider.clone()
 2835    }
 2836
 2837    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2838        self.semantics_provider.clone()
 2839    }
 2840
 2841    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2842        self.semantics_provider = provider;
 2843    }
 2844
 2845    pub fn set_edit_prediction_provider<T>(
 2846        &mut self,
 2847        provider: Option<Entity<T>>,
 2848        window: &mut Window,
 2849        cx: &mut Context<Self>,
 2850    ) where
 2851        T: EditPredictionProvider,
 2852    {
 2853        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2854            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2855                if this.focus_handle.is_focused(window) {
 2856                    this.update_visible_edit_prediction(window, cx);
 2857                }
 2858            }),
 2859            provider: Arc::new(provider),
 2860        });
 2861        self.update_edit_prediction_settings(cx);
 2862        self.refresh_edit_prediction(false, false, window, cx);
 2863    }
 2864
 2865    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2866        self.placeholder_display_map
 2867            .as_ref()
 2868            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2869    }
 2870
 2871    pub fn set_placeholder_text(
 2872        &mut self,
 2873        placeholder_text: &str,
 2874        window: &mut Window,
 2875        cx: &mut Context<Self>,
 2876    ) {
 2877        let multibuffer = cx
 2878            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2879
 2880        let style = window.text_style();
 2881
 2882        self.placeholder_display_map = Some(cx.new(|cx| {
 2883            DisplayMap::new(
 2884                multibuffer,
 2885                style.font(),
 2886                style.font_size.to_pixels(window.rem_size()),
 2887                None,
 2888                FILE_HEADER_HEIGHT,
 2889                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2890                Default::default(),
 2891                DiagnosticSeverity::Off,
 2892                cx,
 2893            )
 2894        }));
 2895        cx.notify();
 2896    }
 2897
 2898    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2899        self.cursor_shape = cursor_shape;
 2900
 2901        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2902        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2903
 2904        cx.notify();
 2905    }
 2906
 2907    pub fn set_current_line_highlight(
 2908        &mut self,
 2909        current_line_highlight: Option<CurrentLineHighlight>,
 2910    ) {
 2911        self.current_line_highlight = current_line_highlight;
 2912    }
 2913
 2914    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2915        self.collapse_matches = collapse_matches;
 2916    }
 2917
 2918    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2919        if self.collapse_matches {
 2920            return range.start..range.start;
 2921        }
 2922        range.clone()
 2923    }
 2924
 2925    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2926        if self.display_map.read(cx).clip_at_line_ends != clip {
 2927            self.display_map
 2928                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2929        }
 2930    }
 2931
 2932    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2933        self.input_enabled = input_enabled;
 2934    }
 2935
 2936    pub fn set_edit_predictions_hidden_for_vim_mode(
 2937        &mut self,
 2938        hidden: bool,
 2939        window: &mut Window,
 2940        cx: &mut Context<Self>,
 2941    ) {
 2942        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2943            self.edit_predictions_hidden_for_vim_mode = hidden;
 2944            if hidden {
 2945                self.update_visible_edit_prediction(window, cx);
 2946            } else {
 2947                self.refresh_edit_prediction(true, false, window, cx);
 2948            }
 2949        }
 2950    }
 2951
 2952    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2953        self.menu_edit_predictions_policy = value;
 2954    }
 2955
 2956    pub fn set_autoindent(&mut self, autoindent: bool) {
 2957        if autoindent {
 2958            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2959        } else {
 2960            self.autoindent_mode = None;
 2961        }
 2962    }
 2963
 2964    pub fn read_only(&self, cx: &App) -> bool {
 2965        self.read_only || self.buffer.read(cx).read_only()
 2966    }
 2967
 2968    pub fn set_read_only(&mut self, read_only: bool) {
 2969        self.read_only = read_only;
 2970    }
 2971
 2972    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2973        self.use_autoclose = autoclose;
 2974    }
 2975
 2976    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2977        self.use_auto_surround = auto_surround;
 2978    }
 2979
 2980    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2981        self.auto_replace_emoji_shortcode = auto_replace;
 2982    }
 2983
 2984    pub fn toggle_edit_predictions(
 2985        &mut self,
 2986        _: &ToggleEditPrediction,
 2987        window: &mut Window,
 2988        cx: &mut Context<Self>,
 2989    ) {
 2990        if self.show_edit_predictions_override.is_some() {
 2991            self.set_show_edit_predictions(None, window, cx);
 2992        } else {
 2993            let show_edit_predictions = !self.edit_predictions_enabled();
 2994            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2995        }
 2996    }
 2997
 2998    pub fn set_show_edit_predictions(
 2999        &mut self,
 3000        show_edit_predictions: Option<bool>,
 3001        window: &mut Window,
 3002        cx: &mut Context<Self>,
 3003    ) {
 3004        self.show_edit_predictions_override = show_edit_predictions;
 3005        self.update_edit_prediction_settings(cx);
 3006
 3007        if let Some(false) = show_edit_predictions {
 3008            self.discard_edit_prediction(false, cx);
 3009        } else {
 3010            self.refresh_edit_prediction(false, true, window, cx);
 3011        }
 3012    }
 3013
 3014    fn edit_predictions_disabled_in_scope(
 3015        &self,
 3016        buffer: &Entity<Buffer>,
 3017        buffer_position: language::Anchor,
 3018        cx: &App,
 3019    ) -> bool {
 3020        let snapshot = buffer.read(cx).snapshot();
 3021        let settings = snapshot.settings_at(buffer_position, cx);
 3022
 3023        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3024            return false;
 3025        };
 3026
 3027        scope.override_name().is_some_and(|scope_name| {
 3028            settings
 3029                .edit_predictions_disabled_in
 3030                .iter()
 3031                .any(|s| s == scope_name)
 3032        })
 3033    }
 3034
 3035    pub fn set_use_modal_editing(&mut self, to: bool) {
 3036        self.use_modal_editing = to;
 3037    }
 3038
 3039    pub fn use_modal_editing(&self) -> bool {
 3040        self.use_modal_editing
 3041    }
 3042
 3043    fn selections_did_change(
 3044        &mut self,
 3045        local: bool,
 3046        old_cursor_position: &Anchor,
 3047        effects: SelectionEffects,
 3048        window: &mut Window,
 3049        cx: &mut Context<Self>,
 3050    ) {
 3051        window.invalidate_character_coordinates();
 3052
 3053        // Copy selections to primary selection buffer
 3054        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3055        if local {
 3056            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3057            let buffer_handle = self.buffer.read(cx).read(cx);
 3058
 3059            let mut text = String::new();
 3060            for (index, selection) in selections.iter().enumerate() {
 3061                let text_for_selection = buffer_handle
 3062                    .text_for_range(selection.start..selection.end)
 3063                    .collect::<String>();
 3064
 3065                text.push_str(&text_for_selection);
 3066                if index != selections.len() - 1 {
 3067                    text.push('\n');
 3068                }
 3069            }
 3070
 3071            if !text.is_empty() {
 3072                cx.write_to_primary(ClipboardItem::new_string(text));
 3073            }
 3074        }
 3075
 3076        let selection_anchors = self.selections.disjoint_anchors_arc();
 3077
 3078        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3079            self.buffer.update(cx, |buffer, cx| {
 3080                buffer.set_active_selections(
 3081                    &selection_anchors,
 3082                    self.selections.line_mode(),
 3083                    self.cursor_shape,
 3084                    cx,
 3085                )
 3086            });
 3087        }
 3088        let display_map = self
 3089            .display_map
 3090            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3091        let buffer = display_map.buffer_snapshot();
 3092        if self.selections.count() == 1 {
 3093            self.add_selections_state = None;
 3094        }
 3095        self.select_next_state = None;
 3096        self.select_prev_state = None;
 3097        self.select_syntax_node_history.try_clear();
 3098        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3099        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3100        self.take_rename(false, window, cx);
 3101
 3102        let newest_selection = self.selections.newest_anchor();
 3103        let new_cursor_position = newest_selection.head();
 3104        let selection_start = newest_selection.start;
 3105
 3106        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3107            self.push_to_nav_history(
 3108                *old_cursor_position,
 3109                Some(new_cursor_position.to_point(buffer)),
 3110                false,
 3111                effects.nav_history == Some(true),
 3112                cx,
 3113            );
 3114        }
 3115
 3116        if local {
 3117            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3118                self.register_buffer(buffer_id, cx);
 3119            }
 3120
 3121            let mut context_menu = self.context_menu.borrow_mut();
 3122            let completion_menu = match context_menu.as_ref() {
 3123                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3124                Some(CodeContextMenu::CodeActions(_)) => {
 3125                    *context_menu = None;
 3126                    None
 3127                }
 3128                None => None,
 3129            };
 3130            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3131            drop(context_menu);
 3132
 3133            if effects.completions
 3134                && let Some(completion_position) = completion_position
 3135            {
 3136                let start_offset = selection_start.to_offset(buffer);
 3137                let position_matches = start_offset == completion_position.to_offset(buffer);
 3138                let continue_showing = if position_matches {
 3139                    if self.snippet_stack.is_empty() {
 3140                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3141                            == Some(CharKind::Word)
 3142                    } else {
 3143                        // Snippet choices can be shown even when the cursor is in whitespace.
 3144                        // Dismissing the menu with actions like backspace is handled by
 3145                        // invalidation regions.
 3146                        true
 3147                    }
 3148                } else {
 3149                    false
 3150                };
 3151
 3152                if continue_showing {
 3153                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3154                } else {
 3155                    self.hide_context_menu(window, cx);
 3156                }
 3157            }
 3158
 3159            hide_hover(self, cx);
 3160
 3161            if old_cursor_position.to_display_point(&display_map).row()
 3162                != new_cursor_position.to_display_point(&display_map).row()
 3163            {
 3164                self.available_code_actions.take();
 3165            }
 3166            self.refresh_code_actions(window, cx);
 3167            self.refresh_document_highlights(cx);
 3168            refresh_linked_ranges(self, window, cx);
 3169
 3170            self.refresh_selected_text_highlights(false, window, cx);
 3171            refresh_matching_bracket_highlights(self, cx);
 3172            self.update_visible_edit_prediction(window, cx);
 3173            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3174            self.inline_blame_popover.take();
 3175            if self.git_blame_inline_enabled {
 3176                self.start_inline_blame_timer(window, cx);
 3177            }
 3178        }
 3179
 3180        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3181        cx.emit(EditorEvent::SelectionsChanged { local });
 3182
 3183        let selections = &self.selections.disjoint_anchors_arc();
 3184        if selections.len() == 1 {
 3185            cx.emit(SearchEvent::ActiveMatchChanged)
 3186        }
 3187        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3188            let inmemory_selections = selections
 3189                .iter()
 3190                .map(|s| {
 3191                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3192                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3193                })
 3194                .collect();
 3195            self.update_restoration_data(cx, |data| {
 3196                data.selections = inmemory_selections;
 3197            });
 3198
 3199            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3200                && let Some(workspace_id) =
 3201                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3202            {
 3203                let snapshot = self.buffer().read(cx).snapshot(cx);
 3204                let selections = selections.clone();
 3205                let background_executor = cx.background_executor().clone();
 3206                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3207                self.serialize_selections = cx.background_spawn(async move {
 3208                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3209                    let db_selections = selections
 3210                        .iter()
 3211                        .map(|selection| {
 3212                            (
 3213                                selection.start.to_offset(&snapshot),
 3214                                selection.end.to_offset(&snapshot),
 3215                            )
 3216                        })
 3217                        .collect();
 3218
 3219                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3220                        .await
 3221                        .with_context(|| {
 3222                            format!(
 3223                                "persisting editor selections for editor {editor_id}, \
 3224                                workspace {workspace_id:?}"
 3225                            )
 3226                        })
 3227                        .log_err();
 3228                });
 3229            }
 3230        }
 3231
 3232        cx.notify();
 3233    }
 3234
 3235    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3236        use text::ToOffset as _;
 3237        use text::ToPoint as _;
 3238
 3239        if self.mode.is_minimap()
 3240            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3241        {
 3242            return;
 3243        }
 3244
 3245        if !self.buffer().read(cx).is_singleton() {
 3246            return;
 3247        }
 3248
 3249        let display_snapshot = self
 3250            .display_map
 3251            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3252        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3253            return;
 3254        };
 3255        let inmemory_folds = display_snapshot
 3256            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3257            .map(|fold| {
 3258                fold.range.start.text_anchor.to_point(&snapshot)
 3259                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3260            })
 3261            .collect();
 3262        self.update_restoration_data(cx, |data| {
 3263            data.folds = inmemory_folds;
 3264        });
 3265
 3266        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3267            return;
 3268        };
 3269        let background_executor = cx.background_executor().clone();
 3270        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3271        let db_folds = display_snapshot
 3272            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3273            .map(|fold| {
 3274                (
 3275                    fold.range.start.text_anchor.to_offset(&snapshot),
 3276                    fold.range.end.text_anchor.to_offset(&snapshot),
 3277                )
 3278            })
 3279            .collect();
 3280        self.serialize_folds = cx.background_spawn(async move {
 3281            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3282            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3283                .await
 3284                .with_context(|| {
 3285                    format!(
 3286                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3287                    )
 3288                })
 3289                .log_err();
 3290        });
 3291    }
 3292
 3293    pub fn sync_selections(
 3294        &mut self,
 3295        other: Entity<Editor>,
 3296        cx: &mut Context<Self>,
 3297    ) -> gpui::Subscription {
 3298        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3299        if !other_selections.is_empty() {
 3300            self.selections.change_with(cx, |selections| {
 3301                selections.select_anchors(other_selections);
 3302            });
 3303        }
 3304
 3305        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3306            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3307                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3308                if other_selections.is_empty() {
 3309                    return;
 3310                }
 3311                this.selections.change_with(cx, |selections| {
 3312                    selections.select_anchors(other_selections);
 3313                });
 3314            }
 3315        });
 3316
 3317        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3318            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3319                let these_selections = this.selections.disjoint_anchors().to_vec();
 3320                if these_selections.is_empty() {
 3321                    return;
 3322                }
 3323                other.update(cx, |other_editor, cx| {
 3324                    other_editor.selections.change_with(cx, |selections| {
 3325                        selections.select_anchors(these_selections);
 3326                    })
 3327                });
 3328            }
 3329        });
 3330
 3331        Subscription::join(other_subscription, this_subscription)
 3332    }
 3333
 3334    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3335    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3336    /// effects of selection change occur at the end of the transaction.
 3337    pub fn change_selections<R>(
 3338        &mut self,
 3339        effects: SelectionEffects,
 3340        window: &mut Window,
 3341        cx: &mut Context<Self>,
 3342        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3343    ) -> R {
 3344        if let Some(state) = &mut self.deferred_selection_effects_state {
 3345            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3346            state.effects.completions = effects.completions;
 3347            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3348            let (changed, result) = self.selections.change_with(cx, change);
 3349            state.changed |= changed;
 3350            return result;
 3351        }
 3352        let mut state = DeferredSelectionEffectsState {
 3353            changed: false,
 3354            effects,
 3355            old_cursor_position: self.selections.newest_anchor().head(),
 3356            history_entry: SelectionHistoryEntry {
 3357                selections: self.selections.disjoint_anchors_arc(),
 3358                select_next_state: self.select_next_state.clone(),
 3359                select_prev_state: self.select_prev_state.clone(),
 3360                add_selections_state: self.add_selections_state.clone(),
 3361            },
 3362        };
 3363        let (changed, result) = self.selections.change_with(cx, change);
 3364        state.changed = state.changed || changed;
 3365        if self.defer_selection_effects {
 3366            self.deferred_selection_effects_state = Some(state);
 3367        } else {
 3368            self.apply_selection_effects(state, window, cx);
 3369        }
 3370        result
 3371    }
 3372
 3373    /// Defers the effects of selection change, so that the effects of multiple calls to
 3374    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3375    /// to selection history and the state of popovers based on selection position aren't
 3376    /// erroneously updated.
 3377    pub fn with_selection_effects_deferred<R>(
 3378        &mut self,
 3379        window: &mut Window,
 3380        cx: &mut Context<Self>,
 3381        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3382    ) -> R {
 3383        let already_deferred = self.defer_selection_effects;
 3384        self.defer_selection_effects = true;
 3385        let result = update(self, window, cx);
 3386        if !already_deferred {
 3387            self.defer_selection_effects = false;
 3388            if let Some(state) = self.deferred_selection_effects_state.take() {
 3389                self.apply_selection_effects(state, window, cx);
 3390            }
 3391        }
 3392        result
 3393    }
 3394
 3395    fn apply_selection_effects(
 3396        &mut self,
 3397        state: DeferredSelectionEffectsState,
 3398        window: &mut Window,
 3399        cx: &mut Context<Self>,
 3400    ) {
 3401        if state.changed {
 3402            self.selection_history.push(state.history_entry);
 3403
 3404            if let Some(autoscroll) = state.effects.scroll {
 3405                self.request_autoscroll(autoscroll, cx);
 3406            }
 3407
 3408            let old_cursor_position = &state.old_cursor_position;
 3409
 3410            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3411
 3412            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3413                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3414            }
 3415        }
 3416    }
 3417
 3418    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3419    where
 3420        I: IntoIterator<Item = (Range<S>, T)>,
 3421        S: ToOffset,
 3422        T: Into<Arc<str>>,
 3423    {
 3424        if self.read_only(cx) {
 3425            return;
 3426        }
 3427
 3428        self.buffer
 3429            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3430    }
 3431
 3432    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3433    where
 3434        I: IntoIterator<Item = (Range<S>, T)>,
 3435        S: ToOffset,
 3436        T: Into<Arc<str>>,
 3437    {
 3438        if self.read_only(cx) {
 3439            return;
 3440        }
 3441
 3442        self.buffer.update(cx, |buffer, cx| {
 3443            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3444        });
 3445    }
 3446
 3447    pub fn edit_with_block_indent<I, S, T>(
 3448        &mut self,
 3449        edits: I,
 3450        original_indent_columns: Vec<Option<u32>>,
 3451        cx: &mut Context<Self>,
 3452    ) where
 3453        I: IntoIterator<Item = (Range<S>, T)>,
 3454        S: ToOffset,
 3455        T: Into<Arc<str>>,
 3456    {
 3457        if self.read_only(cx) {
 3458            return;
 3459        }
 3460
 3461        self.buffer.update(cx, |buffer, cx| {
 3462            buffer.edit(
 3463                edits,
 3464                Some(AutoindentMode::Block {
 3465                    original_indent_columns,
 3466                }),
 3467                cx,
 3468            )
 3469        });
 3470    }
 3471
 3472    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3473        self.hide_context_menu(window, cx);
 3474
 3475        match phase {
 3476            SelectPhase::Begin {
 3477                position,
 3478                add,
 3479                click_count,
 3480            } => self.begin_selection(position, add, click_count, window, cx),
 3481            SelectPhase::BeginColumnar {
 3482                position,
 3483                goal_column,
 3484                reset,
 3485                mode,
 3486            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3487            SelectPhase::Extend {
 3488                position,
 3489                click_count,
 3490            } => self.extend_selection(position, click_count, window, cx),
 3491            SelectPhase::Update {
 3492                position,
 3493                goal_column,
 3494                scroll_delta,
 3495            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3496            SelectPhase::End => self.end_selection(window, cx),
 3497        }
 3498    }
 3499
 3500    fn extend_selection(
 3501        &mut self,
 3502        position: DisplayPoint,
 3503        click_count: usize,
 3504        window: &mut Window,
 3505        cx: &mut Context<Self>,
 3506    ) {
 3507        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3508        let tail = self.selections.newest::<usize>(&display_map).tail();
 3509        let click_count = click_count.max(match self.selections.select_mode() {
 3510            SelectMode::Character => 1,
 3511            SelectMode::Word(_) => 2,
 3512            SelectMode::Line(_) => 3,
 3513            SelectMode::All => 4,
 3514        });
 3515        self.begin_selection(position, false, click_count, window, cx);
 3516
 3517        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3518
 3519        let current_selection = match self.selections.select_mode() {
 3520            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3521            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3522        };
 3523
 3524        let mut pending_selection = self
 3525            .selections
 3526            .pending_anchor()
 3527            .cloned()
 3528            .expect("extend_selection not called with pending selection");
 3529
 3530        if pending_selection
 3531            .start
 3532            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3533            == Ordering::Greater
 3534        {
 3535            pending_selection.start = current_selection.start;
 3536        }
 3537        if pending_selection
 3538            .end
 3539            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3540            == Ordering::Less
 3541        {
 3542            pending_selection.end = current_selection.end;
 3543            pending_selection.reversed = true;
 3544        }
 3545
 3546        let mut pending_mode = self.selections.pending_mode().unwrap();
 3547        match &mut pending_mode {
 3548            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3549            _ => {}
 3550        }
 3551
 3552        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3553            SelectionEffects::scroll(Autoscroll::fit())
 3554        } else {
 3555            SelectionEffects::no_scroll()
 3556        };
 3557
 3558        self.change_selections(effects, window, cx, |s| {
 3559            s.set_pending(pending_selection.clone(), pending_mode);
 3560            s.set_is_extending(true);
 3561        });
 3562    }
 3563
 3564    fn begin_selection(
 3565        &mut self,
 3566        position: DisplayPoint,
 3567        add: bool,
 3568        click_count: usize,
 3569        window: &mut Window,
 3570        cx: &mut Context<Self>,
 3571    ) {
 3572        if !self.focus_handle.is_focused(window) {
 3573            self.last_focused_descendant = None;
 3574            window.focus(&self.focus_handle);
 3575        }
 3576
 3577        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3578        let buffer = display_map.buffer_snapshot();
 3579        let position = display_map.clip_point(position, Bias::Left);
 3580
 3581        let start;
 3582        let end;
 3583        let mode;
 3584        let mut auto_scroll;
 3585        match click_count {
 3586            1 => {
 3587                start = buffer.anchor_before(position.to_point(&display_map));
 3588                end = start;
 3589                mode = SelectMode::Character;
 3590                auto_scroll = true;
 3591            }
 3592            2 => {
 3593                let position = display_map
 3594                    .clip_point(position, Bias::Left)
 3595                    .to_offset(&display_map, Bias::Left);
 3596                let (range, _) = buffer.surrounding_word(position, None);
 3597                start = buffer.anchor_before(range.start);
 3598                end = buffer.anchor_before(range.end);
 3599                mode = SelectMode::Word(start..end);
 3600                auto_scroll = true;
 3601            }
 3602            3 => {
 3603                let position = display_map
 3604                    .clip_point(position, Bias::Left)
 3605                    .to_point(&display_map);
 3606                let line_start = display_map.prev_line_boundary(position).0;
 3607                let next_line_start = buffer.clip_point(
 3608                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3609                    Bias::Left,
 3610                );
 3611                start = buffer.anchor_before(line_start);
 3612                end = buffer.anchor_before(next_line_start);
 3613                mode = SelectMode::Line(start..end);
 3614                auto_scroll = true;
 3615            }
 3616            _ => {
 3617                start = buffer.anchor_before(0);
 3618                end = buffer.anchor_before(buffer.len());
 3619                mode = SelectMode::All;
 3620                auto_scroll = false;
 3621            }
 3622        }
 3623        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3624
 3625        let point_to_delete: Option<usize> = {
 3626            let selected_points: Vec<Selection<Point>> =
 3627                self.selections.disjoint_in_range(start..end, &display_map);
 3628
 3629            if !add || click_count > 1 {
 3630                None
 3631            } else if !selected_points.is_empty() {
 3632                Some(selected_points[0].id)
 3633            } else {
 3634                let clicked_point_already_selected =
 3635                    self.selections.disjoint_anchors().iter().find(|selection| {
 3636                        selection.start.to_point(buffer) == start.to_point(buffer)
 3637                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3638                    });
 3639
 3640                clicked_point_already_selected.map(|selection| selection.id)
 3641            }
 3642        };
 3643
 3644        let selections_count = self.selections.count();
 3645        let effects = if auto_scroll {
 3646            SelectionEffects::default()
 3647        } else {
 3648            SelectionEffects::no_scroll()
 3649        };
 3650
 3651        self.change_selections(effects, window, cx, |s| {
 3652            if let Some(point_to_delete) = point_to_delete {
 3653                s.delete(point_to_delete);
 3654
 3655                if selections_count == 1 {
 3656                    s.set_pending_anchor_range(start..end, mode);
 3657                }
 3658            } else {
 3659                if !add {
 3660                    s.clear_disjoint();
 3661                }
 3662
 3663                s.set_pending_anchor_range(start..end, mode);
 3664            }
 3665        });
 3666    }
 3667
 3668    fn begin_columnar_selection(
 3669        &mut self,
 3670        position: DisplayPoint,
 3671        goal_column: u32,
 3672        reset: bool,
 3673        mode: ColumnarMode,
 3674        window: &mut Window,
 3675        cx: &mut Context<Self>,
 3676    ) {
 3677        if !self.focus_handle.is_focused(window) {
 3678            self.last_focused_descendant = None;
 3679            window.focus(&self.focus_handle);
 3680        }
 3681
 3682        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3683
 3684        if reset {
 3685            let pointer_position = display_map
 3686                .buffer_snapshot()
 3687                .anchor_before(position.to_point(&display_map));
 3688
 3689            self.change_selections(
 3690                SelectionEffects::scroll(Autoscroll::newest()),
 3691                window,
 3692                cx,
 3693                |s| {
 3694                    s.clear_disjoint();
 3695                    s.set_pending_anchor_range(
 3696                        pointer_position..pointer_position,
 3697                        SelectMode::Character,
 3698                    );
 3699                },
 3700            );
 3701        };
 3702
 3703        let tail = self.selections.newest::<Point>(&display_map).tail();
 3704        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3705        self.columnar_selection_state = match mode {
 3706            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3707                selection_tail: selection_anchor,
 3708                display_point: if reset {
 3709                    if position.column() != goal_column {
 3710                        Some(DisplayPoint::new(position.row(), goal_column))
 3711                    } else {
 3712                        None
 3713                    }
 3714                } else {
 3715                    None
 3716                },
 3717            }),
 3718            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3719                selection_tail: selection_anchor,
 3720            }),
 3721        };
 3722
 3723        if !reset {
 3724            self.select_columns(position, goal_column, &display_map, window, cx);
 3725        }
 3726    }
 3727
 3728    fn update_selection(
 3729        &mut self,
 3730        position: DisplayPoint,
 3731        goal_column: u32,
 3732        scroll_delta: gpui::Point<f32>,
 3733        window: &mut Window,
 3734        cx: &mut Context<Self>,
 3735    ) {
 3736        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3737
 3738        if self.columnar_selection_state.is_some() {
 3739            self.select_columns(position, goal_column, &display_map, window, cx);
 3740        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3741            let buffer = display_map.buffer_snapshot();
 3742            let head;
 3743            let tail;
 3744            let mode = self.selections.pending_mode().unwrap();
 3745            match &mode {
 3746                SelectMode::Character => {
 3747                    head = position.to_point(&display_map);
 3748                    tail = pending.tail().to_point(buffer);
 3749                }
 3750                SelectMode::Word(original_range) => {
 3751                    let offset = display_map
 3752                        .clip_point(position, Bias::Left)
 3753                        .to_offset(&display_map, Bias::Left);
 3754                    let original_range = original_range.to_offset(buffer);
 3755
 3756                    let head_offset = if buffer.is_inside_word(offset, None)
 3757                        || original_range.contains(&offset)
 3758                    {
 3759                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3760                        if word_range.start < original_range.start {
 3761                            word_range.start
 3762                        } else {
 3763                            word_range.end
 3764                        }
 3765                    } else {
 3766                        offset
 3767                    };
 3768
 3769                    head = head_offset.to_point(buffer);
 3770                    if head_offset <= original_range.start {
 3771                        tail = original_range.end.to_point(buffer);
 3772                    } else {
 3773                        tail = original_range.start.to_point(buffer);
 3774                    }
 3775                }
 3776                SelectMode::Line(original_range) => {
 3777                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3778
 3779                    let position = display_map
 3780                        .clip_point(position, Bias::Left)
 3781                        .to_point(&display_map);
 3782                    let line_start = display_map.prev_line_boundary(position).0;
 3783                    let next_line_start = buffer.clip_point(
 3784                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3785                        Bias::Left,
 3786                    );
 3787
 3788                    if line_start < original_range.start {
 3789                        head = line_start
 3790                    } else {
 3791                        head = next_line_start
 3792                    }
 3793
 3794                    if head <= original_range.start {
 3795                        tail = original_range.end;
 3796                    } else {
 3797                        tail = original_range.start;
 3798                    }
 3799                }
 3800                SelectMode::All => {
 3801                    return;
 3802                }
 3803            };
 3804
 3805            if head < tail {
 3806                pending.start = buffer.anchor_before(head);
 3807                pending.end = buffer.anchor_before(tail);
 3808                pending.reversed = true;
 3809            } else {
 3810                pending.start = buffer.anchor_before(tail);
 3811                pending.end = buffer.anchor_before(head);
 3812                pending.reversed = false;
 3813            }
 3814
 3815            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3816                s.set_pending(pending.clone(), mode);
 3817            });
 3818        } else {
 3819            log::error!("update_selection dispatched with no pending selection");
 3820            return;
 3821        }
 3822
 3823        self.apply_scroll_delta(scroll_delta, window, cx);
 3824        cx.notify();
 3825    }
 3826
 3827    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3828        self.columnar_selection_state.take();
 3829        if let Some(pending_mode) = self.selections.pending_mode() {
 3830            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3831            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3832                s.select(selections);
 3833                s.clear_pending();
 3834                if s.is_extending() {
 3835                    s.set_is_extending(false);
 3836                } else {
 3837                    s.set_select_mode(pending_mode);
 3838                }
 3839            });
 3840        }
 3841    }
 3842
 3843    fn select_columns(
 3844        &mut self,
 3845        head: DisplayPoint,
 3846        goal_column: u32,
 3847        display_map: &DisplaySnapshot,
 3848        window: &mut Window,
 3849        cx: &mut Context<Self>,
 3850    ) {
 3851        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3852            return;
 3853        };
 3854
 3855        let tail = match columnar_state {
 3856            ColumnarSelectionState::FromMouse {
 3857                selection_tail,
 3858                display_point,
 3859            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3860            ColumnarSelectionState::FromSelection { selection_tail } => {
 3861                selection_tail.to_display_point(display_map)
 3862            }
 3863        };
 3864
 3865        let start_row = cmp::min(tail.row(), head.row());
 3866        let end_row = cmp::max(tail.row(), head.row());
 3867        let start_column = cmp::min(tail.column(), goal_column);
 3868        let end_column = cmp::max(tail.column(), goal_column);
 3869        let reversed = start_column < tail.column();
 3870
 3871        let selection_ranges = (start_row.0..=end_row.0)
 3872            .map(DisplayRow)
 3873            .filter_map(|row| {
 3874                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3875                    || start_column <= display_map.line_len(row))
 3876                    && !display_map.is_block_line(row)
 3877                {
 3878                    let start = display_map
 3879                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3880                        .to_point(display_map);
 3881                    let end = display_map
 3882                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3883                        .to_point(display_map);
 3884                    if reversed {
 3885                        Some(end..start)
 3886                    } else {
 3887                        Some(start..end)
 3888                    }
 3889                } else {
 3890                    None
 3891                }
 3892            })
 3893            .collect::<Vec<_>>();
 3894        if selection_ranges.is_empty() {
 3895            return;
 3896        }
 3897
 3898        let ranges = match columnar_state {
 3899            ColumnarSelectionState::FromMouse { .. } => {
 3900                let mut non_empty_ranges = selection_ranges
 3901                    .iter()
 3902                    .filter(|selection_range| selection_range.start != selection_range.end)
 3903                    .peekable();
 3904                if non_empty_ranges.peek().is_some() {
 3905                    non_empty_ranges.cloned().collect()
 3906                } else {
 3907                    selection_ranges
 3908                }
 3909            }
 3910            _ => selection_ranges,
 3911        };
 3912
 3913        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3914            s.select_ranges(ranges);
 3915        });
 3916        cx.notify();
 3917    }
 3918
 3919    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3920        self.selections
 3921            .all_adjusted(snapshot)
 3922            .iter()
 3923            .any(|selection| !selection.is_empty())
 3924    }
 3925
 3926    pub fn has_pending_nonempty_selection(&self) -> bool {
 3927        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3928            Some(Selection { start, end, .. }) => start != end,
 3929            None => false,
 3930        };
 3931
 3932        pending_nonempty_selection
 3933            || (self.columnar_selection_state.is_some()
 3934                && self.selections.disjoint_anchors().len() > 1)
 3935    }
 3936
 3937    pub fn has_pending_selection(&self) -> bool {
 3938        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3939    }
 3940
 3941    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3942        self.selection_mark_mode = false;
 3943        self.selection_drag_state = SelectionDragState::None;
 3944
 3945        if self.clear_expanded_diff_hunks(cx) {
 3946            cx.notify();
 3947            return;
 3948        }
 3949        if self.dismiss_menus_and_popups(true, window, cx) {
 3950            return;
 3951        }
 3952
 3953        if self.mode.is_full()
 3954            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3955        {
 3956            return;
 3957        }
 3958
 3959        cx.propagate();
 3960    }
 3961
 3962    pub fn dismiss_menus_and_popups(
 3963        &mut self,
 3964        is_user_requested: bool,
 3965        window: &mut Window,
 3966        cx: &mut Context<Self>,
 3967    ) -> bool {
 3968        if self.take_rename(false, window, cx).is_some() {
 3969            return true;
 3970        }
 3971
 3972        if hide_hover(self, cx) {
 3973            return true;
 3974        }
 3975
 3976        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3977            return true;
 3978        }
 3979
 3980        if self.hide_context_menu(window, cx).is_some() {
 3981            return true;
 3982        }
 3983
 3984        if self.mouse_context_menu.take().is_some() {
 3985            return true;
 3986        }
 3987
 3988        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3989            return true;
 3990        }
 3991
 3992        if self.snippet_stack.pop().is_some() {
 3993            return true;
 3994        }
 3995
 3996        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3997            self.dismiss_diagnostics(cx);
 3998            return true;
 3999        }
 4000
 4001        false
 4002    }
 4003
 4004    fn linked_editing_ranges_for(
 4005        &self,
 4006        selection: Range<text::Anchor>,
 4007        cx: &App,
 4008    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4009        if self.linked_edit_ranges.is_empty() {
 4010            return None;
 4011        }
 4012        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4013            selection.end.buffer_id.and_then(|end_buffer_id| {
 4014                if selection.start.buffer_id != Some(end_buffer_id) {
 4015                    return None;
 4016                }
 4017                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4018                let snapshot = buffer.read(cx).snapshot();
 4019                self.linked_edit_ranges
 4020                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4021                    .map(|ranges| (ranges, snapshot, buffer))
 4022            })?;
 4023        use text::ToOffset as TO;
 4024        // find offset from the start of current range to current cursor position
 4025        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4026
 4027        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4028        let start_difference = start_offset - start_byte_offset;
 4029        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4030        let end_difference = end_offset - start_byte_offset;
 4031        // Current range has associated linked ranges.
 4032        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4033        for range in linked_ranges.iter() {
 4034            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4035            let end_offset = start_offset + end_difference;
 4036            let start_offset = start_offset + start_difference;
 4037            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4038                continue;
 4039            }
 4040            if self.selections.disjoint_anchor_ranges().any(|s| {
 4041                if s.start.buffer_id != selection.start.buffer_id
 4042                    || s.end.buffer_id != selection.end.buffer_id
 4043                {
 4044                    return false;
 4045                }
 4046                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4047                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4048            }) {
 4049                continue;
 4050            }
 4051            let start = buffer_snapshot.anchor_after(start_offset);
 4052            let end = buffer_snapshot.anchor_after(end_offset);
 4053            linked_edits
 4054                .entry(buffer.clone())
 4055                .or_default()
 4056                .push(start..end);
 4057        }
 4058        Some(linked_edits)
 4059    }
 4060
 4061    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4062        let text: Arc<str> = text.into();
 4063
 4064        if self.read_only(cx) {
 4065            return;
 4066        }
 4067
 4068        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4069
 4070        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4071        let mut bracket_inserted = false;
 4072        let mut edits = Vec::new();
 4073        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4074        let mut new_selections = Vec::with_capacity(selections.len());
 4075        let mut new_autoclose_regions = Vec::new();
 4076        let snapshot = self.buffer.read(cx).read(cx);
 4077        let mut clear_linked_edit_ranges = false;
 4078
 4079        for (selection, autoclose_region) in
 4080            self.selections_with_autoclose_regions(selections, &snapshot)
 4081        {
 4082            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4083                // Determine if the inserted text matches the opening or closing
 4084                // bracket of any of this language's bracket pairs.
 4085                let mut bracket_pair = None;
 4086                let mut is_bracket_pair_start = false;
 4087                let mut is_bracket_pair_end = false;
 4088                if !text.is_empty() {
 4089                    let mut bracket_pair_matching_end = None;
 4090                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4091                    //  and they are removing the character that triggered IME popup.
 4092                    for (pair, enabled) in scope.brackets() {
 4093                        if !pair.close && !pair.surround {
 4094                            continue;
 4095                        }
 4096
 4097                        if enabled && pair.start.ends_with(text.as_ref()) {
 4098                            let prefix_len = pair.start.len() - text.len();
 4099                            let preceding_text_matches_prefix = prefix_len == 0
 4100                                || (selection.start.column >= (prefix_len as u32)
 4101                                    && snapshot.contains_str_at(
 4102                                        Point::new(
 4103                                            selection.start.row,
 4104                                            selection.start.column - (prefix_len as u32),
 4105                                        ),
 4106                                        &pair.start[..prefix_len],
 4107                                    ));
 4108                            if preceding_text_matches_prefix {
 4109                                bracket_pair = Some(pair.clone());
 4110                                is_bracket_pair_start = true;
 4111                                break;
 4112                            }
 4113                        }
 4114                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4115                        {
 4116                            // take first bracket pair matching end, but don't break in case a later bracket
 4117                            // pair matches start
 4118                            bracket_pair_matching_end = Some(pair.clone());
 4119                        }
 4120                    }
 4121                    if let Some(end) = bracket_pair_matching_end
 4122                        && bracket_pair.is_none()
 4123                    {
 4124                        bracket_pair = Some(end);
 4125                        is_bracket_pair_end = true;
 4126                    }
 4127                }
 4128
 4129                if let Some(bracket_pair) = bracket_pair {
 4130                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4131                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4132                    let auto_surround =
 4133                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4134                    if selection.is_empty() {
 4135                        if is_bracket_pair_start {
 4136                            // If the inserted text is a suffix of an opening bracket and the
 4137                            // selection is preceded by the rest of the opening bracket, then
 4138                            // insert the closing bracket.
 4139                            let following_text_allows_autoclose = snapshot
 4140                                .chars_at(selection.start)
 4141                                .next()
 4142                                .is_none_or(|c| scope.should_autoclose_before(c));
 4143
 4144                            let preceding_text_allows_autoclose = selection.start.column == 0
 4145                                || snapshot
 4146                                    .reversed_chars_at(selection.start)
 4147                                    .next()
 4148                                    .is_none_or(|c| {
 4149                                        bracket_pair.start != bracket_pair.end
 4150                                            || !snapshot
 4151                                                .char_classifier_at(selection.start)
 4152                                                .is_word(c)
 4153                                    });
 4154
 4155                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4156                                && bracket_pair.start.len() == 1
 4157                            {
 4158                                let target = bracket_pair.start.chars().next().unwrap();
 4159                                let current_line_count = snapshot
 4160                                    .reversed_chars_at(selection.start)
 4161                                    .take_while(|&c| c != '\n')
 4162                                    .filter(|&c| c == target)
 4163                                    .count();
 4164                                current_line_count % 2 == 1
 4165                            } else {
 4166                                false
 4167                            };
 4168
 4169                            if autoclose
 4170                                && bracket_pair.close
 4171                                && following_text_allows_autoclose
 4172                                && preceding_text_allows_autoclose
 4173                                && !is_closing_quote
 4174                            {
 4175                                let anchor = snapshot.anchor_before(selection.end);
 4176                                new_selections.push((selection.map(|_| anchor), text.len()));
 4177                                new_autoclose_regions.push((
 4178                                    anchor,
 4179                                    text.len(),
 4180                                    selection.id,
 4181                                    bracket_pair.clone(),
 4182                                ));
 4183                                edits.push((
 4184                                    selection.range(),
 4185                                    format!("{}{}", text, bracket_pair.end).into(),
 4186                                ));
 4187                                bracket_inserted = true;
 4188                                continue;
 4189                            }
 4190                        }
 4191
 4192                        if let Some(region) = autoclose_region {
 4193                            // If the selection is followed by an auto-inserted closing bracket,
 4194                            // then don't insert that closing bracket again; just move the selection
 4195                            // past the closing bracket.
 4196                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4197                                && text.as_ref() == region.pair.end.as_str()
 4198                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4199                            if should_skip {
 4200                                let anchor = snapshot.anchor_after(selection.end);
 4201                                new_selections
 4202                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4203                                continue;
 4204                            }
 4205                        }
 4206
 4207                        let always_treat_brackets_as_autoclosed = snapshot
 4208                            .language_settings_at(selection.start, cx)
 4209                            .always_treat_brackets_as_autoclosed;
 4210                        if always_treat_brackets_as_autoclosed
 4211                            && is_bracket_pair_end
 4212                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4213                        {
 4214                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4215                            // and the inserted text is a closing bracket and the selection is followed
 4216                            // by the closing bracket then move the selection past the closing bracket.
 4217                            let anchor = snapshot.anchor_after(selection.end);
 4218                            new_selections.push((selection.map(|_| anchor), text.len()));
 4219                            continue;
 4220                        }
 4221                    }
 4222                    // If an opening bracket is 1 character long and is typed while
 4223                    // text is selected, then surround that text with the bracket pair.
 4224                    else if auto_surround
 4225                        && bracket_pair.surround
 4226                        && is_bracket_pair_start
 4227                        && bracket_pair.start.chars().count() == 1
 4228                    {
 4229                        edits.push((selection.start..selection.start, text.clone()));
 4230                        edits.push((
 4231                            selection.end..selection.end,
 4232                            bracket_pair.end.as_str().into(),
 4233                        ));
 4234                        bracket_inserted = true;
 4235                        new_selections.push((
 4236                            Selection {
 4237                                id: selection.id,
 4238                                start: snapshot.anchor_after(selection.start),
 4239                                end: snapshot.anchor_before(selection.end),
 4240                                reversed: selection.reversed,
 4241                                goal: selection.goal,
 4242                            },
 4243                            0,
 4244                        ));
 4245                        continue;
 4246                    }
 4247                }
 4248            }
 4249
 4250            if self.auto_replace_emoji_shortcode
 4251                && selection.is_empty()
 4252                && text.as_ref().ends_with(':')
 4253                && let Some(possible_emoji_short_code) =
 4254                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4255                && !possible_emoji_short_code.is_empty()
 4256                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4257            {
 4258                let emoji_shortcode_start = Point::new(
 4259                    selection.start.row,
 4260                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4261                );
 4262
 4263                // Remove shortcode from buffer
 4264                edits.push((
 4265                    emoji_shortcode_start..selection.start,
 4266                    "".to_string().into(),
 4267                ));
 4268                new_selections.push((
 4269                    Selection {
 4270                        id: selection.id,
 4271                        start: snapshot.anchor_after(emoji_shortcode_start),
 4272                        end: snapshot.anchor_before(selection.start),
 4273                        reversed: selection.reversed,
 4274                        goal: selection.goal,
 4275                    },
 4276                    0,
 4277                ));
 4278
 4279                // Insert emoji
 4280                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4281                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4282                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4283
 4284                continue;
 4285            }
 4286
 4287            // If not handling any auto-close operation, then just replace the selected
 4288            // text with the given input and move the selection to the end of the
 4289            // newly inserted text.
 4290            let anchor = snapshot.anchor_after(selection.end);
 4291            if !self.linked_edit_ranges.is_empty() {
 4292                let start_anchor = snapshot.anchor_before(selection.start);
 4293
 4294                let is_word_char = text.chars().next().is_none_or(|char| {
 4295                    let classifier = snapshot
 4296                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4297                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4298                    classifier.is_word(char)
 4299                });
 4300
 4301                if is_word_char {
 4302                    if let Some(ranges) = self
 4303                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4304                    {
 4305                        for (buffer, edits) in ranges {
 4306                            linked_edits
 4307                                .entry(buffer.clone())
 4308                                .or_default()
 4309                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4310                        }
 4311                    }
 4312                } else {
 4313                    clear_linked_edit_ranges = true;
 4314                }
 4315            }
 4316
 4317            new_selections.push((selection.map(|_| anchor), 0));
 4318            edits.push((selection.start..selection.end, text.clone()));
 4319        }
 4320
 4321        drop(snapshot);
 4322
 4323        self.transact(window, cx, |this, window, cx| {
 4324            if clear_linked_edit_ranges {
 4325                this.linked_edit_ranges.clear();
 4326            }
 4327            let initial_buffer_versions =
 4328                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4329
 4330            this.buffer.update(cx, |buffer, cx| {
 4331                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4332            });
 4333            for (buffer, edits) in linked_edits {
 4334                buffer.update(cx, |buffer, cx| {
 4335                    let snapshot = buffer.snapshot();
 4336                    let edits = edits
 4337                        .into_iter()
 4338                        .map(|(range, text)| {
 4339                            use text::ToPoint as TP;
 4340                            let end_point = TP::to_point(&range.end, &snapshot);
 4341                            let start_point = TP::to_point(&range.start, &snapshot);
 4342                            (start_point..end_point, text)
 4343                        })
 4344                        .sorted_by_key(|(range, _)| range.start);
 4345                    buffer.edit(edits, None, cx);
 4346                })
 4347            }
 4348            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4349            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4350            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4351            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4352                .zip(new_selection_deltas)
 4353                .map(|(selection, delta)| Selection {
 4354                    id: selection.id,
 4355                    start: selection.start + delta,
 4356                    end: selection.end + delta,
 4357                    reversed: selection.reversed,
 4358                    goal: SelectionGoal::None,
 4359                })
 4360                .collect::<Vec<_>>();
 4361
 4362            let mut i = 0;
 4363            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4364                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4365                let start = map.buffer_snapshot().anchor_before(position);
 4366                let end = map.buffer_snapshot().anchor_after(position);
 4367                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4368                    match existing_state
 4369                        .range
 4370                        .start
 4371                        .cmp(&start, map.buffer_snapshot())
 4372                    {
 4373                        Ordering::Less => i += 1,
 4374                        Ordering::Greater => break,
 4375                        Ordering::Equal => {
 4376                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4377                                Ordering::Less => i += 1,
 4378                                Ordering::Equal => break,
 4379                                Ordering::Greater => break,
 4380                            }
 4381                        }
 4382                    }
 4383                }
 4384                this.autoclose_regions.insert(
 4385                    i,
 4386                    AutocloseRegion {
 4387                        selection_id,
 4388                        range: start..end,
 4389                        pair,
 4390                    },
 4391                );
 4392            }
 4393
 4394            let had_active_edit_prediction = this.has_active_edit_prediction();
 4395            this.change_selections(
 4396                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4397                window,
 4398                cx,
 4399                |s| s.select(new_selections),
 4400            );
 4401
 4402            if !bracket_inserted
 4403                && let Some(on_type_format_task) =
 4404                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4405            {
 4406                on_type_format_task.detach_and_log_err(cx);
 4407            }
 4408
 4409            let editor_settings = EditorSettings::get_global(cx);
 4410            if bracket_inserted
 4411                && (editor_settings.auto_signature_help
 4412                    || editor_settings.show_signature_help_after_edits)
 4413            {
 4414                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4415            }
 4416
 4417            let trigger_in_words =
 4418                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4419            if this.hard_wrap.is_some() {
 4420                let latest: Range<Point> = this.selections.newest(&map).range();
 4421                if latest.is_empty()
 4422                    && this
 4423                        .buffer()
 4424                        .read(cx)
 4425                        .snapshot(cx)
 4426                        .line_len(MultiBufferRow(latest.start.row))
 4427                        == latest.start.column
 4428                {
 4429                    this.rewrap_impl(
 4430                        RewrapOptions {
 4431                            override_language_settings: true,
 4432                            preserve_existing_whitespace: true,
 4433                        },
 4434                        cx,
 4435                    )
 4436                }
 4437            }
 4438            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4439            refresh_linked_ranges(this, window, cx);
 4440            this.refresh_edit_prediction(true, false, window, cx);
 4441            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4442        });
 4443    }
 4444
 4445    fn find_possible_emoji_shortcode_at_position(
 4446        snapshot: &MultiBufferSnapshot,
 4447        position: Point,
 4448    ) -> Option<String> {
 4449        let mut chars = Vec::new();
 4450        let mut found_colon = false;
 4451        for char in snapshot.reversed_chars_at(position).take(100) {
 4452            // Found a possible emoji shortcode in the middle of the buffer
 4453            if found_colon {
 4454                if char.is_whitespace() {
 4455                    chars.reverse();
 4456                    return Some(chars.iter().collect());
 4457                }
 4458                // If the previous character is not a whitespace, we are in the middle of a word
 4459                // and we only want to complete the shortcode if the word is made up of other emojis
 4460                let mut containing_word = String::new();
 4461                for ch in snapshot
 4462                    .reversed_chars_at(position)
 4463                    .skip(chars.len() + 1)
 4464                    .take(100)
 4465                {
 4466                    if ch.is_whitespace() {
 4467                        break;
 4468                    }
 4469                    containing_word.push(ch);
 4470                }
 4471                let containing_word = containing_word.chars().rev().collect::<String>();
 4472                if util::word_consists_of_emojis(containing_word.as_str()) {
 4473                    chars.reverse();
 4474                    return Some(chars.iter().collect());
 4475                }
 4476            }
 4477
 4478            if char.is_whitespace() || !char.is_ascii() {
 4479                return None;
 4480            }
 4481            if char == ':' {
 4482                found_colon = true;
 4483            } else {
 4484                chars.push(char);
 4485            }
 4486        }
 4487        // Found a possible emoji shortcode at the beginning of the buffer
 4488        chars.reverse();
 4489        Some(chars.iter().collect())
 4490    }
 4491
 4492    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4493        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4494        self.transact(window, cx, |this, window, cx| {
 4495            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4496                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4497                let multi_buffer = this.buffer.read(cx);
 4498                let buffer = multi_buffer.snapshot(cx);
 4499                selections
 4500                    .iter()
 4501                    .map(|selection| {
 4502                        let start_point = selection.start.to_point(&buffer);
 4503                        let mut existing_indent =
 4504                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4505                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4506                        let start = selection.start;
 4507                        let end = selection.end;
 4508                        let selection_is_empty = start == end;
 4509                        let language_scope = buffer.language_scope_at(start);
 4510                        let (
 4511                            comment_delimiter,
 4512                            doc_delimiter,
 4513                            insert_extra_newline,
 4514                            indent_on_newline,
 4515                            indent_on_extra_newline,
 4516                        ) = if let Some(language) = &language_scope {
 4517                            let mut insert_extra_newline =
 4518                                insert_extra_newline_brackets(&buffer, start..end, language)
 4519                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4520
 4521                            // Comment extension on newline is allowed only for cursor selections
 4522                            let comment_delimiter = maybe!({
 4523                                if !selection_is_empty {
 4524                                    return None;
 4525                                }
 4526
 4527                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4528                                    return None;
 4529                                }
 4530
 4531                                let delimiters = language.line_comment_prefixes();
 4532                                let max_len_of_delimiter =
 4533                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4534                                let (snapshot, range) =
 4535                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4536
 4537                                let num_of_whitespaces = snapshot
 4538                                    .chars_for_range(range.clone())
 4539                                    .take_while(|c| c.is_whitespace())
 4540                                    .count();
 4541                                let comment_candidate = snapshot
 4542                                    .chars_for_range(range.clone())
 4543                                    .skip(num_of_whitespaces)
 4544                                    .take(max_len_of_delimiter)
 4545                                    .collect::<String>();
 4546                                let (delimiter, trimmed_len) = delimiters
 4547                                    .iter()
 4548                                    .filter_map(|delimiter| {
 4549                                        let prefix = delimiter.trim_end();
 4550                                        if comment_candidate.starts_with(prefix) {
 4551                                            Some((delimiter, prefix.len()))
 4552                                        } else {
 4553                                            None
 4554                                        }
 4555                                    })
 4556                                    .max_by_key(|(_, len)| *len)?;
 4557
 4558                                if let Some(BlockCommentConfig {
 4559                                    start: block_start, ..
 4560                                }) = language.block_comment()
 4561                                {
 4562                                    let block_start_trimmed = block_start.trim_end();
 4563                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4564                                        let line_content = snapshot
 4565                                            .chars_for_range(range)
 4566                                            .skip(num_of_whitespaces)
 4567                                            .take(block_start_trimmed.len())
 4568                                            .collect::<String>();
 4569
 4570                                        if line_content.starts_with(block_start_trimmed) {
 4571                                            return None;
 4572                                        }
 4573                                    }
 4574                                }
 4575
 4576                                let cursor_is_placed_after_comment_marker =
 4577                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4578                                if cursor_is_placed_after_comment_marker {
 4579                                    Some(delimiter.clone())
 4580                                } else {
 4581                                    None
 4582                                }
 4583                            });
 4584
 4585                            let mut indent_on_newline = IndentSize::spaces(0);
 4586                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4587
 4588                            let doc_delimiter = maybe!({
 4589                                if !selection_is_empty {
 4590                                    return None;
 4591                                }
 4592
 4593                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4594                                    return None;
 4595                                }
 4596
 4597                                let BlockCommentConfig {
 4598                                    start: start_tag,
 4599                                    end: end_tag,
 4600                                    prefix: delimiter,
 4601                                    tab_size: len,
 4602                                } = language.documentation_comment()?;
 4603                                let is_within_block_comment = buffer
 4604                                    .language_scope_at(start_point)
 4605                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4606                                if !is_within_block_comment {
 4607                                    return None;
 4608                                }
 4609
 4610                                let (snapshot, range) =
 4611                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4612
 4613                                let num_of_whitespaces = snapshot
 4614                                    .chars_for_range(range.clone())
 4615                                    .take_while(|c| c.is_whitespace())
 4616                                    .count();
 4617
 4618                                // 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.
 4619                                let column = start_point.column;
 4620                                let cursor_is_after_start_tag = {
 4621                                    let start_tag_len = start_tag.len();
 4622                                    let start_tag_line = snapshot
 4623                                        .chars_for_range(range.clone())
 4624                                        .skip(num_of_whitespaces)
 4625                                        .take(start_tag_len)
 4626                                        .collect::<String>();
 4627                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4628                                        num_of_whitespaces + start_tag_len <= column as usize
 4629                                    } else {
 4630                                        false
 4631                                    }
 4632                                };
 4633
 4634                                let cursor_is_after_delimiter = {
 4635                                    let delimiter_trim = delimiter.trim_end();
 4636                                    let delimiter_line = snapshot
 4637                                        .chars_for_range(range.clone())
 4638                                        .skip(num_of_whitespaces)
 4639                                        .take(delimiter_trim.len())
 4640                                        .collect::<String>();
 4641                                    if delimiter_line.starts_with(delimiter_trim) {
 4642                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4643                                    } else {
 4644                                        false
 4645                                    }
 4646                                };
 4647
 4648                                let cursor_is_before_end_tag_if_exists = {
 4649                                    let mut char_position = 0u32;
 4650                                    let mut end_tag_offset = None;
 4651
 4652                                    'outer: for chunk in snapshot.text_for_range(range) {
 4653                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4654                                            let chars_before_match =
 4655                                                chunk[..byte_pos].chars().count() as u32;
 4656                                            end_tag_offset =
 4657                                                Some(char_position + chars_before_match);
 4658                                            break 'outer;
 4659                                        }
 4660                                        char_position += chunk.chars().count() as u32;
 4661                                    }
 4662
 4663                                    if let Some(end_tag_offset) = end_tag_offset {
 4664                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4665                                        if cursor_is_after_start_tag {
 4666                                            if cursor_is_before_end_tag {
 4667                                                insert_extra_newline = true;
 4668                                            }
 4669                                            let cursor_is_at_start_of_end_tag =
 4670                                                column == end_tag_offset;
 4671                                            if cursor_is_at_start_of_end_tag {
 4672                                                indent_on_extra_newline.len = *len;
 4673                                            }
 4674                                        }
 4675                                        cursor_is_before_end_tag
 4676                                    } else {
 4677                                        true
 4678                                    }
 4679                                };
 4680
 4681                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4682                                    && cursor_is_before_end_tag_if_exists
 4683                                {
 4684                                    if cursor_is_after_start_tag {
 4685                                        indent_on_newline.len = *len;
 4686                                    }
 4687                                    Some(delimiter.clone())
 4688                                } else {
 4689                                    None
 4690                                }
 4691                            });
 4692
 4693                            (
 4694                                comment_delimiter,
 4695                                doc_delimiter,
 4696                                insert_extra_newline,
 4697                                indent_on_newline,
 4698                                indent_on_extra_newline,
 4699                            )
 4700                        } else {
 4701                            (
 4702                                None,
 4703                                None,
 4704                                false,
 4705                                IndentSize::default(),
 4706                                IndentSize::default(),
 4707                            )
 4708                        };
 4709
 4710                        let prevent_auto_indent = doc_delimiter.is_some();
 4711                        let delimiter = comment_delimiter.or(doc_delimiter);
 4712
 4713                        let capacity_for_delimiter =
 4714                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4715                        let mut new_text = String::with_capacity(
 4716                            1 + capacity_for_delimiter
 4717                                + existing_indent.len as usize
 4718                                + indent_on_newline.len as usize
 4719                                + indent_on_extra_newline.len as usize,
 4720                        );
 4721                        new_text.push('\n');
 4722                        new_text.extend(existing_indent.chars());
 4723                        new_text.extend(indent_on_newline.chars());
 4724
 4725                        if let Some(delimiter) = &delimiter {
 4726                            new_text.push_str(delimiter);
 4727                        }
 4728
 4729                        if insert_extra_newline {
 4730                            new_text.push('\n');
 4731                            new_text.extend(existing_indent.chars());
 4732                            new_text.extend(indent_on_extra_newline.chars());
 4733                        }
 4734
 4735                        let anchor = buffer.anchor_after(end);
 4736                        let new_selection = selection.map(|_| anchor);
 4737                        (
 4738                            ((start..end, new_text), prevent_auto_indent),
 4739                            (insert_extra_newline, new_selection),
 4740                        )
 4741                    })
 4742                    .unzip()
 4743            };
 4744
 4745            let mut auto_indent_edits = Vec::new();
 4746            let mut edits = Vec::new();
 4747            for (edit, prevent_auto_indent) in edits_with_flags {
 4748                if prevent_auto_indent {
 4749                    edits.push(edit);
 4750                } else {
 4751                    auto_indent_edits.push(edit);
 4752                }
 4753            }
 4754            if !edits.is_empty() {
 4755                this.edit(edits, cx);
 4756            }
 4757            if !auto_indent_edits.is_empty() {
 4758                this.edit_with_autoindent(auto_indent_edits, cx);
 4759            }
 4760
 4761            let buffer = this.buffer.read(cx).snapshot(cx);
 4762            let new_selections = selection_info
 4763                .into_iter()
 4764                .map(|(extra_newline_inserted, new_selection)| {
 4765                    let mut cursor = new_selection.end.to_point(&buffer);
 4766                    if extra_newline_inserted {
 4767                        cursor.row -= 1;
 4768                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4769                    }
 4770                    new_selection.map(|_| cursor)
 4771                })
 4772                .collect();
 4773
 4774            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4775            this.refresh_edit_prediction(true, false, window, cx);
 4776        });
 4777    }
 4778
 4779    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4781
 4782        let buffer = self.buffer.read(cx);
 4783        let snapshot = buffer.snapshot(cx);
 4784
 4785        let mut edits = Vec::new();
 4786        let mut rows = Vec::new();
 4787
 4788        for (rows_inserted, selection) in self
 4789            .selections
 4790            .all_adjusted(&self.display_snapshot(cx))
 4791            .into_iter()
 4792            .enumerate()
 4793        {
 4794            let cursor = selection.head();
 4795            let row = cursor.row;
 4796
 4797            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4798
 4799            let newline = "\n".to_string();
 4800            edits.push((start_of_line..start_of_line, newline));
 4801
 4802            rows.push(row + rows_inserted as u32);
 4803        }
 4804
 4805        self.transact(window, cx, |editor, window, cx| {
 4806            editor.edit(edits, cx);
 4807
 4808            editor.change_selections(Default::default(), window, cx, |s| {
 4809                let mut index = 0;
 4810                s.move_cursors_with(|map, _, _| {
 4811                    let row = rows[index];
 4812                    index += 1;
 4813
 4814                    let point = Point::new(row, 0);
 4815                    let boundary = map.next_line_boundary(point).1;
 4816                    let clipped = map.clip_point(boundary, Bias::Left);
 4817
 4818                    (clipped, SelectionGoal::None)
 4819                });
 4820            });
 4821
 4822            let mut indent_edits = Vec::new();
 4823            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4824            for row in rows {
 4825                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4826                for (row, indent) in indents {
 4827                    if indent.len == 0 {
 4828                        continue;
 4829                    }
 4830
 4831                    let text = match indent.kind {
 4832                        IndentKind::Space => " ".repeat(indent.len as usize),
 4833                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4834                    };
 4835                    let point = Point::new(row.0, 0);
 4836                    indent_edits.push((point..point, text));
 4837                }
 4838            }
 4839            editor.edit(indent_edits, cx);
 4840        });
 4841    }
 4842
 4843    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4845
 4846        let buffer = self.buffer.read(cx);
 4847        let snapshot = buffer.snapshot(cx);
 4848
 4849        let mut edits = Vec::new();
 4850        let mut rows = Vec::new();
 4851        let mut rows_inserted = 0;
 4852
 4853        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4854            let cursor = selection.head();
 4855            let row = cursor.row;
 4856
 4857            let point = Point::new(row + 1, 0);
 4858            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4859
 4860            let newline = "\n".to_string();
 4861            edits.push((start_of_line..start_of_line, newline));
 4862
 4863            rows_inserted += 1;
 4864            rows.push(row + rows_inserted);
 4865        }
 4866
 4867        self.transact(window, cx, |editor, window, cx| {
 4868            editor.edit(edits, cx);
 4869
 4870            editor.change_selections(Default::default(), window, cx, |s| {
 4871                let mut index = 0;
 4872                s.move_cursors_with(|map, _, _| {
 4873                    let row = rows[index];
 4874                    index += 1;
 4875
 4876                    let point = Point::new(row, 0);
 4877                    let boundary = map.next_line_boundary(point).1;
 4878                    let clipped = map.clip_point(boundary, Bias::Left);
 4879
 4880                    (clipped, SelectionGoal::None)
 4881                });
 4882            });
 4883
 4884            let mut indent_edits = Vec::new();
 4885            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4886            for row in rows {
 4887                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4888                for (row, indent) in indents {
 4889                    if indent.len == 0 {
 4890                        continue;
 4891                    }
 4892
 4893                    let text = match indent.kind {
 4894                        IndentKind::Space => " ".repeat(indent.len as usize),
 4895                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4896                    };
 4897                    let point = Point::new(row.0, 0);
 4898                    indent_edits.push((point..point, text));
 4899                }
 4900            }
 4901            editor.edit(indent_edits, cx);
 4902        });
 4903    }
 4904
 4905    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4906        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4907            original_indent_columns: Vec::new(),
 4908        });
 4909        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4910    }
 4911
 4912    fn insert_with_autoindent_mode(
 4913        &mut self,
 4914        text: &str,
 4915        autoindent_mode: Option<AutoindentMode>,
 4916        window: &mut Window,
 4917        cx: &mut Context<Self>,
 4918    ) {
 4919        if self.read_only(cx) {
 4920            return;
 4921        }
 4922
 4923        let text: Arc<str> = text.into();
 4924        self.transact(window, cx, |this, window, cx| {
 4925            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4926            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4927                let anchors = {
 4928                    let snapshot = buffer.read(cx);
 4929                    old_selections
 4930                        .iter()
 4931                        .map(|s| {
 4932                            let anchor = snapshot.anchor_after(s.head());
 4933                            s.map(|_| anchor)
 4934                        })
 4935                        .collect::<Vec<_>>()
 4936                };
 4937                buffer.edit(
 4938                    old_selections
 4939                        .iter()
 4940                        .map(|s| (s.start..s.end, text.clone())),
 4941                    autoindent_mode,
 4942                    cx,
 4943                );
 4944                anchors
 4945            });
 4946
 4947            this.change_selections(Default::default(), window, cx, |s| {
 4948                s.select_anchors(selection_anchors);
 4949            });
 4950
 4951            cx.notify();
 4952        });
 4953    }
 4954
 4955    fn trigger_completion_on_input(
 4956        &mut self,
 4957        text: &str,
 4958        trigger_in_words: bool,
 4959        window: &mut Window,
 4960        cx: &mut Context<Self>,
 4961    ) {
 4962        let completions_source = self
 4963            .context_menu
 4964            .borrow()
 4965            .as_ref()
 4966            .and_then(|menu| match menu {
 4967                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4968                CodeContextMenu::CodeActions(_) => None,
 4969            });
 4970
 4971        match completions_source {
 4972            Some(CompletionsMenuSource::Words { .. }) => {
 4973                self.open_or_update_completions_menu(
 4974                    Some(CompletionsMenuSource::Words {
 4975                        ignore_threshold: false,
 4976                    }),
 4977                    None,
 4978                    window,
 4979                    cx,
 4980                );
 4981            }
 4982            Some(CompletionsMenuSource::Normal)
 4983            | Some(CompletionsMenuSource::SnippetChoices)
 4984            | None
 4985                if self.is_completion_trigger(
 4986                    text,
 4987                    trigger_in_words,
 4988                    completions_source.is_some(),
 4989                    cx,
 4990                ) =>
 4991            {
 4992                self.show_completions(
 4993                    &ShowCompletions {
 4994                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4995                    },
 4996                    window,
 4997                    cx,
 4998                )
 4999            }
 5000            _ => {
 5001                self.hide_context_menu(window, cx);
 5002            }
 5003        }
 5004    }
 5005
 5006    fn is_completion_trigger(
 5007        &self,
 5008        text: &str,
 5009        trigger_in_words: bool,
 5010        menu_is_open: bool,
 5011        cx: &mut Context<Self>,
 5012    ) -> bool {
 5013        let position = self.selections.newest_anchor().head();
 5014        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5015            return false;
 5016        };
 5017
 5018        if let Some(completion_provider) = &self.completion_provider {
 5019            completion_provider.is_completion_trigger(
 5020                &buffer,
 5021                position.text_anchor,
 5022                text,
 5023                trigger_in_words,
 5024                menu_is_open,
 5025                cx,
 5026            )
 5027        } else {
 5028            false
 5029        }
 5030    }
 5031
 5032    /// If any empty selections is touching the start of its innermost containing autoclose
 5033    /// region, expand it to select the brackets.
 5034    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5035        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5036        let buffer = self.buffer.read(cx).read(cx);
 5037        let new_selections = self
 5038            .selections_with_autoclose_regions(selections, &buffer)
 5039            .map(|(mut selection, region)| {
 5040                if !selection.is_empty() {
 5041                    return selection;
 5042                }
 5043
 5044                if let Some(region) = region {
 5045                    let mut range = region.range.to_offset(&buffer);
 5046                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5047                        range.start -= region.pair.start.len();
 5048                        if buffer.contains_str_at(range.start, &region.pair.start)
 5049                            && buffer.contains_str_at(range.end, &region.pair.end)
 5050                        {
 5051                            range.end += region.pair.end.len();
 5052                            selection.start = range.start;
 5053                            selection.end = range.end;
 5054
 5055                            return selection;
 5056                        }
 5057                    }
 5058                }
 5059
 5060                let always_treat_brackets_as_autoclosed = buffer
 5061                    .language_settings_at(selection.start, cx)
 5062                    .always_treat_brackets_as_autoclosed;
 5063
 5064                if !always_treat_brackets_as_autoclosed {
 5065                    return selection;
 5066                }
 5067
 5068                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5069                    for (pair, enabled) in scope.brackets() {
 5070                        if !enabled || !pair.close {
 5071                            continue;
 5072                        }
 5073
 5074                        if buffer.contains_str_at(selection.start, &pair.end) {
 5075                            let pair_start_len = pair.start.len();
 5076                            if buffer.contains_str_at(
 5077                                selection.start.saturating_sub(pair_start_len),
 5078                                &pair.start,
 5079                            ) {
 5080                                selection.start -= pair_start_len;
 5081                                selection.end += pair.end.len();
 5082
 5083                                return selection;
 5084                            }
 5085                        }
 5086                    }
 5087                }
 5088
 5089                selection
 5090            })
 5091            .collect();
 5092
 5093        drop(buffer);
 5094        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5095            selections.select(new_selections)
 5096        });
 5097    }
 5098
 5099    /// Iterate the given selections, and for each one, find the smallest surrounding
 5100    /// autoclose region. This uses the ordering of the selections and the autoclose
 5101    /// regions to avoid repeated comparisons.
 5102    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5103        &'a self,
 5104        selections: impl IntoIterator<Item = Selection<D>>,
 5105        buffer: &'a MultiBufferSnapshot,
 5106    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5107        let mut i = 0;
 5108        let mut regions = self.autoclose_regions.as_slice();
 5109        selections.into_iter().map(move |selection| {
 5110            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5111
 5112            let mut enclosing = None;
 5113            while let Some(pair_state) = regions.get(i) {
 5114                if pair_state.range.end.to_offset(buffer) < range.start {
 5115                    regions = &regions[i + 1..];
 5116                    i = 0;
 5117                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5118                    break;
 5119                } else {
 5120                    if pair_state.selection_id == selection.id {
 5121                        enclosing = Some(pair_state);
 5122                    }
 5123                    i += 1;
 5124                }
 5125            }
 5126
 5127            (selection, enclosing)
 5128        })
 5129    }
 5130
 5131    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5132    fn invalidate_autoclose_regions(
 5133        &mut self,
 5134        mut selections: &[Selection<Anchor>],
 5135        buffer: &MultiBufferSnapshot,
 5136    ) {
 5137        self.autoclose_regions.retain(|state| {
 5138            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5139                return false;
 5140            }
 5141
 5142            let mut i = 0;
 5143            while let Some(selection) = selections.get(i) {
 5144                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5145                    selections = &selections[1..];
 5146                    continue;
 5147                }
 5148                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5149                    break;
 5150                }
 5151                if selection.id == state.selection_id {
 5152                    return true;
 5153                } else {
 5154                    i += 1;
 5155                }
 5156            }
 5157            false
 5158        });
 5159    }
 5160
 5161    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5162        let offset = position.to_offset(buffer);
 5163        let (word_range, kind) =
 5164            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5165        if offset > word_range.start && kind == Some(CharKind::Word) {
 5166            Some(
 5167                buffer
 5168                    .text_for_range(word_range.start..offset)
 5169                    .collect::<String>(),
 5170            )
 5171        } else {
 5172            None
 5173        }
 5174    }
 5175
 5176    pub fn toggle_inline_values(
 5177        &mut self,
 5178        _: &ToggleInlineValues,
 5179        _: &mut Window,
 5180        cx: &mut Context<Self>,
 5181    ) {
 5182        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5183
 5184        self.refresh_inline_values(cx);
 5185    }
 5186
 5187    pub fn toggle_inlay_hints(
 5188        &mut self,
 5189        _: &ToggleInlayHints,
 5190        _: &mut Window,
 5191        cx: &mut Context<Self>,
 5192    ) {
 5193        self.refresh_inlay_hints(
 5194            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5195            cx,
 5196        );
 5197    }
 5198
 5199    pub fn inlay_hints_enabled(&self) -> bool {
 5200        self.inlay_hint_cache.enabled
 5201    }
 5202
 5203    pub fn inline_values_enabled(&self) -> bool {
 5204        self.inline_value_cache.enabled
 5205    }
 5206
 5207    #[cfg(any(test, feature = "test-support"))]
 5208    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5209        self.display_map
 5210            .read(cx)
 5211            .current_inlays()
 5212            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5213            .cloned()
 5214            .collect()
 5215    }
 5216
 5217    #[cfg(any(test, feature = "test-support"))]
 5218    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5219        self.display_map
 5220            .read(cx)
 5221            .current_inlays()
 5222            .cloned()
 5223            .collect()
 5224    }
 5225
 5226    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5227        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5228            return;
 5229        }
 5230
 5231        let reason_description = reason.description();
 5232        let ignore_debounce = matches!(
 5233            reason,
 5234            InlayHintRefreshReason::SettingsChange(_)
 5235                | InlayHintRefreshReason::Toggle(_)
 5236                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5237                | InlayHintRefreshReason::ModifiersChanged(_)
 5238        );
 5239        let (invalidate_cache, required_languages) = match reason {
 5240            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5241                match self.inlay_hint_cache.modifiers_override(enabled) {
 5242                    Some(enabled) => {
 5243                        if enabled {
 5244                            (InvalidationStrategy::RefreshRequested, None)
 5245                        } else {
 5246                            self.clear_inlay_hints(cx);
 5247                            return;
 5248                        }
 5249                    }
 5250                    None => return,
 5251                }
 5252            }
 5253            InlayHintRefreshReason::Toggle(enabled) => {
 5254                if self.inlay_hint_cache.toggle(enabled) {
 5255                    if enabled {
 5256                        (InvalidationStrategy::RefreshRequested, None)
 5257                    } else {
 5258                        self.clear_inlay_hints(cx);
 5259                        return;
 5260                    }
 5261                } else {
 5262                    return;
 5263                }
 5264            }
 5265            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5266                match self.inlay_hint_cache.update_settings(
 5267                    &self.buffer,
 5268                    new_settings,
 5269                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5270                    cx,
 5271                ) {
 5272                    ControlFlow::Break(Some(InlaySplice {
 5273                        to_remove,
 5274                        to_insert,
 5275                    })) => {
 5276                        self.splice_inlays(&to_remove, to_insert, cx);
 5277                        return;
 5278                    }
 5279                    ControlFlow::Break(None) => return,
 5280                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5281                }
 5282            }
 5283            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5284                if let Some(InlaySplice {
 5285                    to_remove,
 5286                    to_insert,
 5287                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5288                {
 5289                    self.splice_inlays(&to_remove, to_insert, cx);
 5290                }
 5291                self.display_map.update(cx, |display_map, _| {
 5292                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5293                });
 5294                return;
 5295            }
 5296            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5297            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5298                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5299            }
 5300            InlayHintRefreshReason::RefreshRequested => {
 5301                (InvalidationStrategy::RefreshRequested, None)
 5302            }
 5303        };
 5304
 5305        let mut visible_excerpts = self.visible_excerpts(required_languages.as_ref(), cx);
 5306        visible_excerpts.retain(|_, (buffer, _, _)| {
 5307            self.registered_buffers
 5308                .contains_key(&buffer.read(cx).remote_id())
 5309        });
 5310
 5311        if let Some(InlaySplice {
 5312            to_remove,
 5313            to_insert,
 5314        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5315            reason_description,
 5316            visible_excerpts,
 5317            invalidate_cache,
 5318            ignore_debounce,
 5319            cx,
 5320        ) {
 5321            self.splice_inlays(&to_remove, to_insert, cx);
 5322        }
 5323    }
 5324
 5325    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5326        self.splice_inlays(
 5327            &self
 5328                .visible_inlay_hints(cx)
 5329                .map(|inlay| inlay.id)
 5330                .collect::<Vec<_>>(),
 5331            Vec::new(),
 5332            cx,
 5333        );
 5334    }
 5335
 5336    fn visible_inlay_hints<'a>(
 5337        &'a self,
 5338        cx: &'a Context<Editor>,
 5339    ) -> impl Iterator<Item = &'a Inlay> {
 5340        self.display_map
 5341            .read(cx)
 5342            .current_inlays()
 5343            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5344    }
 5345
 5346    pub fn visible_excerpts(
 5347        &self,
 5348        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5349        cx: &mut Context<Editor>,
 5350    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5351        let Some(project) = self.project() else {
 5352            return HashMap::default();
 5353        };
 5354        let project = project.read(cx);
 5355        let multi_buffer = self.buffer().read(cx);
 5356        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5357        let multi_buffer_visible_start = self
 5358            .scroll_manager
 5359            .anchor()
 5360            .anchor
 5361            .to_point(&multi_buffer_snapshot);
 5362        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5363            multi_buffer_visible_start
 5364                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5365            Bias::Left,
 5366        );
 5367        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5368        multi_buffer_snapshot
 5369            .range_to_buffer_ranges(multi_buffer_visible_range)
 5370            .into_iter()
 5371            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5372            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5373                let buffer_file = project::File::from_dyn(buffer.file())?;
 5374                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5375                let worktree_entry = buffer_worktree
 5376                    .read(cx)
 5377                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5378                if worktree_entry.is_ignored {
 5379                    return None;
 5380                }
 5381
 5382                let language = buffer.language()?;
 5383                if let Some(restrict_to_languages) = restrict_to_languages
 5384                    && !restrict_to_languages.contains(language)
 5385                {
 5386                    return None;
 5387                }
 5388                Some((
 5389                    excerpt_id,
 5390                    (
 5391                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5392                        buffer.version().clone(),
 5393                        excerpt_visible_range,
 5394                    ),
 5395                ))
 5396            })
 5397            .collect()
 5398    }
 5399
 5400    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5401        TextLayoutDetails {
 5402            text_system: window.text_system().clone(),
 5403            editor_style: self.style.clone().unwrap(),
 5404            rem_size: window.rem_size(),
 5405            scroll_anchor: self.scroll_manager.anchor(),
 5406            visible_rows: self.visible_line_count(),
 5407            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5408        }
 5409    }
 5410
 5411    pub fn splice_inlays(
 5412        &self,
 5413        to_remove: &[InlayId],
 5414        to_insert: Vec<Inlay>,
 5415        cx: &mut Context<Self>,
 5416    ) {
 5417        self.display_map.update(cx, |display_map, cx| {
 5418            display_map.splice_inlays(to_remove, to_insert, cx)
 5419        });
 5420        cx.notify();
 5421    }
 5422
 5423    fn trigger_on_type_formatting(
 5424        &self,
 5425        input: String,
 5426        window: &mut Window,
 5427        cx: &mut Context<Self>,
 5428    ) -> Option<Task<Result<()>>> {
 5429        if input.len() != 1 {
 5430            return None;
 5431        }
 5432
 5433        let project = self.project()?;
 5434        let position = self.selections.newest_anchor().head();
 5435        let (buffer, buffer_position) = self
 5436            .buffer
 5437            .read(cx)
 5438            .text_anchor_for_position(position, cx)?;
 5439
 5440        let settings = language_settings::language_settings(
 5441            buffer
 5442                .read(cx)
 5443                .language_at(buffer_position)
 5444                .map(|l| l.name()),
 5445            buffer.read(cx).file(),
 5446            cx,
 5447        );
 5448        if !settings.use_on_type_format {
 5449            return None;
 5450        }
 5451
 5452        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5453        // hence we do LSP request & edit on host side only — add formats to host's history.
 5454        let push_to_lsp_host_history = true;
 5455        // If this is not the host, append its history with new edits.
 5456        let push_to_client_history = project.read(cx).is_via_collab();
 5457
 5458        let on_type_formatting = project.update(cx, |project, cx| {
 5459            project.on_type_format(
 5460                buffer.clone(),
 5461                buffer_position,
 5462                input,
 5463                push_to_lsp_host_history,
 5464                cx,
 5465            )
 5466        });
 5467        Some(cx.spawn_in(window, async move |editor, cx| {
 5468            if let Some(transaction) = on_type_formatting.await? {
 5469                if push_to_client_history {
 5470                    buffer
 5471                        .update(cx, |buffer, _| {
 5472                            buffer.push_transaction(transaction, Instant::now());
 5473                            buffer.finalize_last_transaction();
 5474                        })
 5475                        .ok();
 5476                }
 5477                editor.update(cx, |editor, cx| {
 5478                    editor.refresh_document_highlights(cx);
 5479                })?;
 5480            }
 5481            Ok(())
 5482        }))
 5483    }
 5484
 5485    pub fn show_word_completions(
 5486        &mut self,
 5487        _: &ShowWordCompletions,
 5488        window: &mut Window,
 5489        cx: &mut Context<Self>,
 5490    ) {
 5491        self.open_or_update_completions_menu(
 5492            Some(CompletionsMenuSource::Words {
 5493                ignore_threshold: true,
 5494            }),
 5495            None,
 5496            window,
 5497            cx,
 5498        );
 5499    }
 5500
 5501    pub fn show_completions(
 5502        &mut self,
 5503        options: &ShowCompletions,
 5504        window: &mut Window,
 5505        cx: &mut Context<Self>,
 5506    ) {
 5507        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5508    }
 5509
 5510    fn open_or_update_completions_menu(
 5511        &mut self,
 5512        requested_source: Option<CompletionsMenuSource>,
 5513        trigger: Option<&str>,
 5514        window: &mut Window,
 5515        cx: &mut Context<Self>,
 5516    ) {
 5517        if self.pending_rename.is_some() {
 5518            return;
 5519        }
 5520
 5521        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5522
 5523        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5524        // inserted and selected. To handle that case, the start of the selection is used so that
 5525        // the menu starts with all choices.
 5526        let position = self
 5527            .selections
 5528            .newest_anchor()
 5529            .start
 5530            .bias_right(&multibuffer_snapshot);
 5531        if position.diff_base_anchor.is_some() {
 5532            return;
 5533        }
 5534        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5535        let Some(buffer) = buffer_position
 5536            .buffer_id
 5537            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5538        else {
 5539            return;
 5540        };
 5541        let buffer_snapshot = buffer.read(cx).snapshot();
 5542
 5543        let query: Option<Arc<String>> =
 5544            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5545                .map(|query| query.into());
 5546
 5547        drop(multibuffer_snapshot);
 5548
 5549        // Hide the current completions menu when query is empty. Without this, cached
 5550        // completions from before the trigger char may be reused (#32774).
 5551        if query.is_none() {
 5552            let menu_is_open = matches!(
 5553                self.context_menu.borrow().as_ref(),
 5554                Some(CodeContextMenu::Completions(_))
 5555            );
 5556            if menu_is_open {
 5557                self.hide_context_menu(window, cx);
 5558            }
 5559        }
 5560
 5561        let mut ignore_word_threshold = false;
 5562        let provider = match requested_source {
 5563            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5564            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5565                ignore_word_threshold = ignore_threshold;
 5566                None
 5567            }
 5568            Some(CompletionsMenuSource::SnippetChoices) => {
 5569                log::error!("bug: SnippetChoices requested_source is not handled");
 5570                None
 5571            }
 5572        };
 5573
 5574        let sort_completions = provider
 5575            .as_ref()
 5576            .is_some_and(|provider| provider.sort_completions());
 5577
 5578        let filter_completions = provider
 5579            .as_ref()
 5580            .is_none_or(|provider| provider.filter_completions());
 5581
 5582        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5583            if filter_completions {
 5584                menu.filter(query.clone(), provider.clone(), window, cx);
 5585            }
 5586            // When `is_incomplete` is false, no need to re-query completions when the current query
 5587            // is a suffix of the initial query.
 5588            if !menu.is_incomplete {
 5589                // If the new query is a suffix of the old query (typing more characters) and
 5590                // the previous result was complete, the existing completions can be filtered.
 5591                //
 5592                // Note that this is always true for snippet completions.
 5593                let query_matches = match (&menu.initial_query, &query) {
 5594                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5595                    (None, _) => true,
 5596                    _ => false,
 5597                };
 5598                if query_matches {
 5599                    let position_matches = if menu.initial_position == position {
 5600                        true
 5601                    } else {
 5602                        let snapshot = self.buffer.read(cx).read(cx);
 5603                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5604                    };
 5605                    if position_matches {
 5606                        return;
 5607                    }
 5608                }
 5609            }
 5610        };
 5611
 5612        let trigger_kind = match trigger {
 5613            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5614                CompletionTriggerKind::TRIGGER_CHARACTER
 5615            }
 5616            _ => CompletionTriggerKind::INVOKED,
 5617        };
 5618        let completion_context = CompletionContext {
 5619            trigger_character: trigger.and_then(|trigger| {
 5620                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5621                    Some(String::from(trigger))
 5622                } else {
 5623                    None
 5624                }
 5625            }),
 5626            trigger_kind,
 5627        };
 5628
 5629        let Anchor {
 5630            excerpt_id: buffer_excerpt_id,
 5631            text_anchor: buffer_position,
 5632            ..
 5633        } = buffer_position;
 5634
 5635        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5636            buffer_snapshot.surrounding_word(buffer_position, None)
 5637        {
 5638            let word_to_exclude = buffer_snapshot
 5639                .text_for_range(word_range.clone())
 5640                .collect::<String>();
 5641            (
 5642                buffer_snapshot.anchor_before(word_range.start)
 5643                    ..buffer_snapshot.anchor_after(buffer_position),
 5644                Some(word_to_exclude),
 5645            )
 5646        } else {
 5647            (buffer_position..buffer_position, None)
 5648        };
 5649
 5650        let language = buffer_snapshot
 5651            .language_at(buffer_position)
 5652            .map(|language| language.name());
 5653
 5654        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5655            .completions
 5656            .clone();
 5657
 5658        let show_completion_documentation = buffer_snapshot
 5659            .settings_at(buffer_position, cx)
 5660            .show_completion_documentation;
 5661
 5662        // The document can be large, so stay in reasonable bounds when searching for words,
 5663        // otherwise completion pop-up might be slow to appear.
 5664        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5665        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5666        let min_word_search = buffer_snapshot.clip_point(
 5667            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5668            Bias::Left,
 5669        );
 5670        let max_word_search = buffer_snapshot.clip_point(
 5671            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5672            Bias::Right,
 5673        );
 5674        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5675            ..buffer_snapshot.point_to_offset(max_word_search);
 5676
 5677        let skip_digits = query
 5678            .as_ref()
 5679            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5680
 5681        let omit_word_completions = !self.word_completions_enabled
 5682            || (!ignore_word_threshold
 5683                && match &query {
 5684                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5685                    None => completion_settings.words_min_length != 0,
 5686                });
 5687
 5688        let (mut words, provider_responses) = match &provider {
 5689            Some(provider) => {
 5690                let provider_responses = provider.completions(
 5691                    buffer_excerpt_id,
 5692                    &buffer,
 5693                    buffer_position,
 5694                    completion_context,
 5695                    window,
 5696                    cx,
 5697                );
 5698
 5699                let words = match (omit_word_completions, completion_settings.words) {
 5700                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5701                        Task::ready(BTreeMap::default())
 5702                    }
 5703                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5704                        .background_spawn(async move {
 5705                            buffer_snapshot.words_in_range(WordsQuery {
 5706                                fuzzy_contents: None,
 5707                                range: word_search_range,
 5708                                skip_digits,
 5709                            })
 5710                        }),
 5711                };
 5712
 5713                (words, provider_responses)
 5714            }
 5715            None => {
 5716                let words = if omit_word_completions {
 5717                    Task::ready(BTreeMap::default())
 5718                } else {
 5719                    cx.background_spawn(async move {
 5720                        buffer_snapshot.words_in_range(WordsQuery {
 5721                            fuzzy_contents: None,
 5722                            range: word_search_range,
 5723                            skip_digits,
 5724                        })
 5725                    })
 5726                };
 5727                (words, Task::ready(Ok(Vec::new())))
 5728            }
 5729        };
 5730
 5731        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5732
 5733        let id = post_inc(&mut self.next_completion_id);
 5734        let task = cx.spawn_in(window, async move |editor, cx| {
 5735            let Ok(()) = editor.update(cx, |this, _| {
 5736                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5737            }) else {
 5738                return;
 5739            };
 5740
 5741            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5742            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5743            let mut completions = Vec::new();
 5744            let mut is_incomplete = false;
 5745            let mut display_options: Option<CompletionDisplayOptions> = None;
 5746            if let Some(provider_responses) = provider_responses.await.log_err()
 5747                && !provider_responses.is_empty()
 5748            {
 5749                for response in provider_responses {
 5750                    completions.extend(response.completions);
 5751                    is_incomplete = is_incomplete || response.is_incomplete;
 5752                    match display_options.as_mut() {
 5753                        None => {
 5754                            display_options = Some(response.display_options);
 5755                        }
 5756                        Some(options) => options.merge(&response.display_options),
 5757                    }
 5758                }
 5759                if completion_settings.words == WordsCompletionMode::Fallback {
 5760                    words = Task::ready(BTreeMap::default());
 5761                }
 5762            }
 5763            let display_options = display_options.unwrap_or_default();
 5764
 5765            let mut words = words.await;
 5766            if let Some(word_to_exclude) = &word_to_exclude {
 5767                words.remove(word_to_exclude);
 5768            }
 5769            for lsp_completion in &completions {
 5770                words.remove(&lsp_completion.new_text);
 5771            }
 5772            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5773                replace_range: word_replace_range.clone(),
 5774                new_text: word.clone(),
 5775                label: CodeLabel::plain(word, None),
 5776                icon_path: None,
 5777                documentation: None,
 5778                source: CompletionSource::BufferWord {
 5779                    word_range,
 5780                    resolved: false,
 5781                },
 5782                insert_text_mode: Some(InsertTextMode::AS_IS),
 5783                confirm: None,
 5784            }));
 5785
 5786            let menu = if completions.is_empty() {
 5787                None
 5788            } else {
 5789                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5790                    let languages = editor
 5791                        .workspace
 5792                        .as_ref()
 5793                        .and_then(|(workspace, _)| workspace.upgrade())
 5794                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5795                    let menu = CompletionsMenu::new(
 5796                        id,
 5797                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5798                        sort_completions,
 5799                        show_completion_documentation,
 5800                        position,
 5801                        query.clone(),
 5802                        is_incomplete,
 5803                        buffer.clone(),
 5804                        completions.into(),
 5805                        display_options,
 5806                        snippet_sort_order,
 5807                        languages,
 5808                        language,
 5809                        cx,
 5810                    );
 5811
 5812                    let query = if filter_completions { query } else { None };
 5813                    let matches_task = if let Some(query) = query {
 5814                        menu.do_async_filtering(query, cx)
 5815                    } else {
 5816                        Task::ready(menu.unfiltered_matches())
 5817                    };
 5818                    (menu, matches_task)
 5819                }) else {
 5820                    return;
 5821                };
 5822
 5823                let matches = matches_task.await;
 5824
 5825                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5826                    // Newer menu already set, so exit.
 5827                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5828                        editor.context_menu.borrow().as_ref()
 5829                        && prev_menu.id > id
 5830                    {
 5831                        return;
 5832                    };
 5833
 5834                    // Only valid to take prev_menu because it the new menu is immediately set
 5835                    // below, or the menu is hidden.
 5836                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5837                        editor.context_menu.borrow_mut().take()
 5838                    {
 5839                        let position_matches =
 5840                            if prev_menu.initial_position == menu.initial_position {
 5841                                true
 5842                            } else {
 5843                                let snapshot = editor.buffer.read(cx).read(cx);
 5844                                prev_menu.initial_position.to_offset(&snapshot)
 5845                                    == menu.initial_position.to_offset(&snapshot)
 5846                            };
 5847                        if position_matches {
 5848                            // Preserve markdown cache before `set_filter_results` because it will
 5849                            // try to populate the documentation cache.
 5850                            menu.preserve_markdown_cache(prev_menu);
 5851                        }
 5852                    };
 5853
 5854                    menu.set_filter_results(matches, provider, window, cx);
 5855                }) else {
 5856                    return;
 5857                };
 5858
 5859                menu.visible().then_some(menu)
 5860            };
 5861
 5862            editor
 5863                .update_in(cx, |editor, window, cx| {
 5864                    if editor.focus_handle.is_focused(window)
 5865                        && let Some(menu) = menu
 5866                    {
 5867                        *editor.context_menu.borrow_mut() =
 5868                            Some(CodeContextMenu::Completions(menu));
 5869
 5870                        crate::hover_popover::hide_hover(editor, cx);
 5871                        if editor.show_edit_predictions_in_menu() {
 5872                            editor.update_visible_edit_prediction(window, cx);
 5873                        } else {
 5874                            editor.discard_edit_prediction(false, cx);
 5875                        }
 5876
 5877                        cx.notify();
 5878                        return;
 5879                    }
 5880
 5881                    if editor.completion_tasks.len() <= 1 {
 5882                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5883                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5884                        // If it was already hidden and we don't show edit predictions in the menu,
 5885                        // we should also show the edit prediction when available.
 5886                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5887                            editor.update_visible_edit_prediction(window, cx);
 5888                        }
 5889                    }
 5890                })
 5891                .ok();
 5892        });
 5893
 5894        self.completion_tasks.push((id, task));
 5895    }
 5896
 5897    #[cfg(feature = "test-support")]
 5898    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5899        let menu = self.context_menu.borrow();
 5900        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5901            let completions = menu.completions.borrow();
 5902            Some(completions.to_vec())
 5903        } else {
 5904            None
 5905        }
 5906    }
 5907
 5908    pub fn with_completions_menu_matching_id<R>(
 5909        &self,
 5910        id: CompletionId,
 5911        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5912    ) -> R {
 5913        let mut context_menu = self.context_menu.borrow_mut();
 5914        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5915            return f(None);
 5916        };
 5917        if completions_menu.id != id {
 5918            return f(None);
 5919        }
 5920        f(Some(completions_menu))
 5921    }
 5922
 5923    pub fn confirm_completion(
 5924        &mut self,
 5925        action: &ConfirmCompletion,
 5926        window: &mut Window,
 5927        cx: &mut Context<Self>,
 5928    ) -> Option<Task<Result<()>>> {
 5929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5930        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5931    }
 5932
 5933    pub fn confirm_completion_insert(
 5934        &mut self,
 5935        _: &ConfirmCompletionInsert,
 5936        window: &mut Window,
 5937        cx: &mut Context<Self>,
 5938    ) -> Option<Task<Result<()>>> {
 5939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5940        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5941    }
 5942
 5943    pub fn confirm_completion_replace(
 5944        &mut self,
 5945        _: &ConfirmCompletionReplace,
 5946        window: &mut Window,
 5947        cx: &mut Context<Self>,
 5948    ) -> Option<Task<Result<()>>> {
 5949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5950        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5951    }
 5952
 5953    pub fn compose_completion(
 5954        &mut self,
 5955        action: &ComposeCompletion,
 5956        window: &mut Window,
 5957        cx: &mut Context<Self>,
 5958    ) -> Option<Task<Result<()>>> {
 5959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5960        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5961    }
 5962
 5963    fn do_completion(
 5964        &mut self,
 5965        item_ix: Option<usize>,
 5966        intent: CompletionIntent,
 5967        window: &mut Window,
 5968        cx: &mut Context<Editor>,
 5969    ) -> Option<Task<Result<()>>> {
 5970        use language::ToOffset as _;
 5971
 5972        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5973        else {
 5974            return None;
 5975        };
 5976
 5977        let candidate_id = {
 5978            let entries = completions_menu.entries.borrow();
 5979            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5980            if self.show_edit_predictions_in_menu() {
 5981                self.discard_edit_prediction(true, cx);
 5982            }
 5983            mat.candidate_id
 5984        };
 5985
 5986        let completion = completions_menu
 5987            .completions
 5988            .borrow()
 5989            .get(candidate_id)?
 5990            .clone();
 5991        cx.stop_propagation();
 5992
 5993        let buffer_handle = completions_menu.buffer.clone();
 5994
 5995        let CompletionEdit {
 5996            new_text,
 5997            snippet,
 5998            replace_range,
 5999        } = process_completion_for_edit(
 6000            &completion,
 6001            intent,
 6002            &buffer_handle,
 6003            &completions_menu.initial_position.text_anchor,
 6004            cx,
 6005        );
 6006
 6007        let buffer = buffer_handle.read(cx);
 6008        let snapshot = self.buffer.read(cx).snapshot(cx);
 6009        let newest_anchor = self.selections.newest_anchor();
 6010        let replace_range_multibuffer = {
 6011            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6012            excerpt.map_range_from_buffer(replace_range.clone())
 6013        };
 6014        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6015            return None;
 6016        }
 6017
 6018        let old_text = buffer
 6019            .text_for_range(replace_range.clone())
 6020            .collect::<String>();
 6021        let lookbehind = newest_anchor
 6022            .start
 6023            .text_anchor
 6024            .to_offset(buffer)
 6025            .saturating_sub(replace_range.start);
 6026        let lookahead = replace_range
 6027            .end
 6028            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6029        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6030        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6031
 6032        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6033        let mut ranges = Vec::new();
 6034        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6035
 6036        for selection in &selections {
 6037            let range = if selection.id == newest_anchor.id {
 6038                replace_range_multibuffer.clone()
 6039            } else {
 6040                let mut range = selection.range();
 6041
 6042                // if prefix is present, don't duplicate it
 6043                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6044                    range.start = range.start.saturating_sub(lookbehind);
 6045
 6046                    // if suffix is also present, mimic the newest cursor and replace it
 6047                    if selection.id != newest_anchor.id
 6048                        && snapshot.contains_str_at(range.end, suffix)
 6049                    {
 6050                        range.end += lookahead;
 6051                    }
 6052                }
 6053                range
 6054            };
 6055
 6056            ranges.push(range.clone());
 6057
 6058            if !self.linked_edit_ranges.is_empty() {
 6059                let start_anchor = snapshot.anchor_before(range.start);
 6060                let end_anchor = snapshot.anchor_after(range.end);
 6061                if let Some(ranges) = self
 6062                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6063                {
 6064                    for (buffer, edits) in ranges {
 6065                        linked_edits
 6066                            .entry(buffer.clone())
 6067                            .or_default()
 6068                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6069                    }
 6070                }
 6071            }
 6072        }
 6073
 6074        let common_prefix_len = old_text
 6075            .chars()
 6076            .zip(new_text.chars())
 6077            .take_while(|(a, b)| a == b)
 6078            .map(|(a, _)| a.len_utf8())
 6079            .sum::<usize>();
 6080
 6081        cx.emit(EditorEvent::InputHandled {
 6082            utf16_range_to_replace: None,
 6083            text: new_text[common_prefix_len..].into(),
 6084        });
 6085
 6086        self.transact(window, cx, |editor, window, cx| {
 6087            if let Some(mut snippet) = snippet {
 6088                snippet.text = new_text.to_string();
 6089                editor
 6090                    .insert_snippet(&ranges, snippet, window, cx)
 6091                    .log_err();
 6092            } else {
 6093                editor.buffer.update(cx, |multi_buffer, cx| {
 6094                    let auto_indent = match completion.insert_text_mode {
 6095                        Some(InsertTextMode::AS_IS) => None,
 6096                        _ => editor.autoindent_mode.clone(),
 6097                    };
 6098                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6099                    multi_buffer.edit(edits, auto_indent, cx);
 6100                });
 6101            }
 6102            for (buffer, edits) in linked_edits {
 6103                buffer.update(cx, |buffer, cx| {
 6104                    let snapshot = buffer.snapshot();
 6105                    let edits = edits
 6106                        .into_iter()
 6107                        .map(|(range, text)| {
 6108                            use text::ToPoint as TP;
 6109                            let end_point = TP::to_point(&range.end, &snapshot);
 6110                            let start_point = TP::to_point(&range.start, &snapshot);
 6111                            (start_point..end_point, text)
 6112                        })
 6113                        .sorted_by_key(|(range, _)| range.start);
 6114                    buffer.edit(edits, None, cx);
 6115                })
 6116            }
 6117
 6118            editor.refresh_edit_prediction(true, false, window, cx);
 6119        });
 6120        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6121
 6122        let show_new_completions_on_confirm = completion
 6123            .confirm
 6124            .as_ref()
 6125            .is_some_and(|confirm| confirm(intent, window, cx));
 6126        if show_new_completions_on_confirm {
 6127            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6128        }
 6129
 6130        let provider = self.completion_provider.as_ref()?;
 6131        drop(completion);
 6132        let apply_edits = provider.apply_additional_edits_for_completion(
 6133            buffer_handle,
 6134            completions_menu.completions.clone(),
 6135            candidate_id,
 6136            true,
 6137            cx,
 6138        );
 6139
 6140        let editor_settings = EditorSettings::get_global(cx);
 6141        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6142            // After the code completion is finished, users often want to know what signatures are needed.
 6143            // so we should automatically call signature_help
 6144            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6145        }
 6146
 6147        Some(cx.foreground_executor().spawn(async move {
 6148            apply_edits.await?;
 6149            Ok(())
 6150        }))
 6151    }
 6152
 6153    pub fn toggle_code_actions(
 6154        &mut self,
 6155        action: &ToggleCodeActions,
 6156        window: &mut Window,
 6157        cx: &mut Context<Self>,
 6158    ) {
 6159        let quick_launch = action.quick_launch;
 6160        let mut context_menu = self.context_menu.borrow_mut();
 6161        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6162            if code_actions.deployed_from == action.deployed_from {
 6163                // Toggle if we're selecting the same one
 6164                *context_menu = None;
 6165                cx.notify();
 6166                return;
 6167            } else {
 6168                // Otherwise, clear it and start a new one
 6169                *context_menu = None;
 6170                cx.notify();
 6171            }
 6172        }
 6173        drop(context_menu);
 6174        let snapshot = self.snapshot(window, cx);
 6175        let deployed_from = action.deployed_from.clone();
 6176        let action = action.clone();
 6177        self.completion_tasks.clear();
 6178        self.discard_edit_prediction(false, cx);
 6179
 6180        let multibuffer_point = match &action.deployed_from {
 6181            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6182                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6183            }
 6184            _ => self
 6185                .selections
 6186                .newest::<Point>(&snapshot.display_snapshot)
 6187                .head(),
 6188        };
 6189        let Some((buffer, buffer_row)) = snapshot
 6190            .buffer_snapshot()
 6191            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6192            .and_then(|(buffer_snapshot, range)| {
 6193                self.buffer()
 6194                    .read(cx)
 6195                    .buffer(buffer_snapshot.remote_id())
 6196                    .map(|buffer| (buffer, range.start.row))
 6197            })
 6198        else {
 6199            return;
 6200        };
 6201        let buffer_id = buffer.read(cx).remote_id();
 6202        let tasks = self
 6203            .tasks
 6204            .get(&(buffer_id, buffer_row))
 6205            .map(|t| Arc::new(t.to_owned()));
 6206
 6207        if !self.focus_handle.is_focused(window) {
 6208            return;
 6209        }
 6210        let project = self.project.clone();
 6211
 6212        let code_actions_task = match deployed_from {
 6213            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6214            _ => self.code_actions(buffer_row, window, cx),
 6215        };
 6216
 6217        let runnable_task = match deployed_from {
 6218            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6219            _ => {
 6220                let mut task_context_task = Task::ready(None);
 6221                if let Some(tasks) = &tasks
 6222                    && let Some(project) = project
 6223                {
 6224                    task_context_task =
 6225                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6226                }
 6227
 6228                cx.spawn_in(window, {
 6229                    let buffer = buffer.clone();
 6230                    async move |editor, cx| {
 6231                        let task_context = task_context_task.await;
 6232
 6233                        let resolved_tasks =
 6234                            tasks
 6235                                .zip(task_context.clone())
 6236                                .map(|(tasks, task_context)| ResolvedTasks {
 6237                                    templates: tasks.resolve(&task_context).collect(),
 6238                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6239                                        multibuffer_point.row,
 6240                                        tasks.column,
 6241                                    )),
 6242                                });
 6243                        let debug_scenarios = editor
 6244                            .update(cx, |editor, cx| {
 6245                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6246                            })?
 6247                            .await;
 6248                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6249                    }
 6250                })
 6251            }
 6252        };
 6253
 6254        cx.spawn_in(window, async move |editor, cx| {
 6255            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6256            let code_actions = code_actions_task.await;
 6257            let spawn_straight_away = quick_launch
 6258                && resolved_tasks
 6259                    .as_ref()
 6260                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6261                && code_actions
 6262                    .as_ref()
 6263                    .is_none_or(|actions| actions.is_empty())
 6264                && debug_scenarios.is_empty();
 6265
 6266            editor.update_in(cx, |editor, window, cx| {
 6267                crate::hover_popover::hide_hover(editor, cx);
 6268                let actions = CodeActionContents::new(
 6269                    resolved_tasks,
 6270                    code_actions,
 6271                    debug_scenarios,
 6272                    task_context.unwrap_or_default(),
 6273                );
 6274
 6275                // Don't show the menu if there are no actions available
 6276                if actions.is_empty() {
 6277                    cx.notify();
 6278                    return Task::ready(Ok(()));
 6279                }
 6280
 6281                *editor.context_menu.borrow_mut() =
 6282                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6283                        buffer,
 6284                        actions,
 6285                        selected_item: Default::default(),
 6286                        scroll_handle: UniformListScrollHandle::default(),
 6287                        deployed_from,
 6288                    }));
 6289                cx.notify();
 6290                if spawn_straight_away
 6291                    && let Some(task) = editor.confirm_code_action(
 6292                        &ConfirmCodeAction { item_ix: Some(0) },
 6293                        window,
 6294                        cx,
 6295                    )
 6296                {
 6297                    return task;
 6298                }
 6299
 6300                Task::ready(Ok(()))
 6301            })
 6302        })
 6303        .detach_and_log_err(cx);
 6304    }
 6305
 6306    fn debug_scenarios(
 6307        &mut self,
 6308        resolved_tasks: &Option<ResolvedTasks>,
 6309        buffer: &Entity<Buffer>,
 6310        cx: &mut App,
 6311    ) -> Task<Vec<task::DebugScenario>> {
 6312        maybe!({
 6313            let project = self.project()?;
 6314            let dap_store = project.read(cx).dap_store();
 6315            let mut scenarios = vec![];
 6316            let resolved_tasks = resolved_tasks.as_ref()?;
 6317            let buffer = buffer.read(cx);
 6318            let language = buffer.language()?;
 6319            let file = buffer.file();
 6320            let debug_adapter = language_settings(language.name().into(), file, cx)
 6321                .debuggers
 6322                .first()
 6323                .map(SharedString::from)
 6324                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6325
 6326            dap_store.update(cx, |dap_store, cx| {
 6327                for (_, task) in &resolved_tasks.templates {
 6328                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6329                        task.original_task().clone(),
 6330                        debug_adapter.clone().into(),
 6331                        task.display_label().to_owned().into(),
 6332                        cx,
 6333                    );
 6334                    scenarios.push(maybe_scenario);
 6335                }
 6336            });
 6337            Some(cx.background_spawn(async move {
 6338                futures::future::join_all(scenarios)
 6339                    .await
 6340                    .into_iter()
 6341                    .flatten()
 6342                    .collect::<Vec<_>>()
 6343            }))
 6344        })
 6345        .unwrap_or_else(|| Task::ready(vec![]))
 6346    }
 6347
 6348    fn code_actions(
 6349        &mut self,
 6350        buffer_row: u32,
 6351        window: &mut Window,
 6352        cx: &mut Context<Self>,
 6353    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6354        let mut task = self.code_actions_task.take();
 6355        cx.spawn_in(window, async move |editor, cx| {
 6356            while let Some(prev_task) = task {
 6357                prev_task.await.log_err();
 6358                task = editor
 6359                    .update(cx, |this, _| this.code_actions_task.take())
 6360                    .ok()?;
 6361            }
 6362
 6363            editor
 6364                .update(cx, |editor, cx| {
 6365                    editor
 6366                        .available_code_actions
 6367                        .clone()
 6368                        .and_then(|(location, code_actions)| {
 6369                            let snapshot = location.buffer.read(cx).snapshot();
 6370                            let point_range = location.range.to_point(&snapshot);
 6371                            let point_range = point_range.start.row..=point_range.end.row;
 6372                            if point_range.contains(&buffer_row) {
 6373                                Some(code_actions)
 6374                            } else {
 6375                                None
 6376                            }
 6377                        })
 6378                })
 6379                .ok()
 6380                .flatten()
 6381        })
 6382    }
 6383
 6384    pub fn confirm_code_action(
 6385        &mut self,
 6386        action: &ConfirmCodeAction,
 6387        window: &mut Window,
 6388        cx: &mut Context<Self>,
 6389    ) -> Option<Task<Result<()>>> {
 6390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6391
 6392        let actions_menu =
 6393            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6394                menu
 6395            } else {
 6396                return None;
 6397            };
 6398
 6399        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6400        let action = actions_menu.actions.get(action_ix)?;
 6401        let title = action.label();
 6402        let buffer = actions_menu.buffer;
 6403        let workspace = self.workspace()?;
 6404
 6405        match action {
 6406            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6407                workspace.update(cx, |workspace, cx| {
 6408                    workspace.schedule_resolved_task(
 6409                        task_source_kind,
 6410                        resolved_task,
 6411                        false,
 6412                        window,
 6413                        cx,
 6414                    );
 6415
 6416                    Some(Task::ready(Ok(())))
 6417                })
 6418            }
 6419            CodeActionsItem::CodeAction {
 6420                excerpt_id,
 6421                action,
 6422                provider,
 6423            } => {
 6424                let apply_code_action =
 6425                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6426                let workspace = workspace.downgrade();
 6427                Some(cx.spawn_in(window, async move |editor, cx| {
 6428                    let project_transaction = apply_code_action.await?;
 6429                    Self::open_project_transaction(
 6430                        &editor,
 6431                        workspace,
 6432                        project_transaction,
 6433                        title,
 6434                        cx,
 6435                    )
 6436                    .await
 6437                }))
 6438            }
 6439            CodeActionsItem::DebugScenario(scenario) => {
 6440                let context = actions_menu.actions.context;
 6441
 6442                workspace.update(cx, |workspace, cx| {
 6443                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6444                    workspace.start_debug_session(
 6445                        scenario,
 6446                        context,
 6447                        Some(buffer),
 6448                        None,
 6449                        window,
 6450                        cx,
 6451                    );
 6452                });
 6453                Some(Task::ready(Ok(())))
 6454            }
 6455        }
 6456    }
 6457
 6458    pub async fn open_project_transaction(
 6459        editor: &WeakEntity<Editor>,
 6460        workspace: WeakEntity<Workspace>,
 6461        transaction: ProjectTransaction,
 6462        title: String,
 6463        cx: &mut AsyncWindowContext,
 6464    ) -> Result<()> {
 6465        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6466        cx.update(|_, cx| {
 6467            entries.sort_unstable_by_key(|(buffer, _)| {
 6468                buffer.read(cx).file().map(|f| f.path().clone())
 6469            });
 6470        })?;
 6471        if entries.is_empty() {
 6472            return Ok(());
 6473        }
 6474
 6475        // If the project transaction's edits are all contained within this editor, then
 6476        // avoid opening a new editor to display them.
 6477
 6478        if let [(buffer, transaction)] = &*entries {
 6479            let excerpt = editor.update(cx, |editor, cx| {
 6480                editor
 6481                    .buffer()
 6482                    .read(cx)
 6483                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6484            })?;
 6485            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6486                && excerpted_buffer == *buffer
 6487            {
 6488                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6489                    let excerpt_range = excerpt_range.to_offset(buffer);
 6490                    buffer
 6491                        .edited_ranges_for_transaction::<usize>(transaction)
 6492                        .all(|range| {
 6493                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6494                        })
 6495                })?;
 6496
 6497                if all_edits_within_excerpt {
 6498                    return Ok(());
 6499                }
 6500            }
 6501        }
 6502
 6503        let mut ranges_to_highlight = Vec::new();
 6504        let excerpt_buffer = cx.new(|cx| {
 6505            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6506            for (buffer_handle, transaction) in &entries {
 6507                let edited_ranges = buffer_handle
 6508                    .read(cx)
 6509                    .edited_ranges_for_transaction::<Point>(transaction)
 6510                    .collect::<Vec<_>>();
 6511                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6512                    PathKey::for_buffer(buffer_handle, cx),
 6513                    buffer_handle.clone(),
 6514                    edited_ranges,
 6515                    multibuffer_context_lines(cx),
 6516                    cx,
 6517                );
 6518
 6519                ranges_to_highlight.extend(ranges);
 6520            }
 6521            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6522            multibuffer
 6523        })?;
 6524
 6525        workspace.update_in(cx, |workspace, window, cx| {
 6526            let project = workspace.project().clone();
 6527            let editor =
 6528                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6529            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6530            editor.update(cx, |editor, cx| {
 6531                editor.highlight_background::<Self>(
 6532                    &ranges_to_highlight,
 6533                    |theme| theme.colors().editor_highlighted_line_background,
 6534                    cx,
 6535                );
 6536            });
 6537        })?;
 6538
 6539        Ok(())
 6540    }
 6541
 6542    pub fn clear_code_action_providers(&mut self) {
 6543        self.code_action_providers.clear();
 6544        self.available_code_actions.take();
 6545    }
 6546
 6547    pub fn add_code_action_provider(
 6548        &mut self,
 6549        provider: Rc<dyn CodeActionProvider>,
 6550        window: &mut Window,
 6551        cx: &mut Context<Self>,
 6552    ) {
 6553        if self
 6554            .code_action_providers
 6555            .iter()
 6556            .any(|existing_provider| existing_provider.id() == provider.id())
 6557        {
 6558            return;
 6559        }
 6560
 6561        self.code_action_providers.push(provider);
 6562        self.refresh_code_actions(window, cx);
 6563    }
 6564
 6565    pub fn remove_code_action_provider(
 6566        &mut self,
 6567        id: Arc<str>,
 6568        window: &mut Window,
 6569        cx: &mut Context<Self>,
 6570    ) {
 6571        self.code_action_providers
 6572            .retain(|provider| provider.id() != id);
 6573        self.refresh_code_actions(window, cx);
 6574    }
 6575
 6576    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6577        !self.code_action_providers.is_empty()
 6578            && EditorSettings::get_global(cx).toolbar.code_actions
 6579    }
 6580
 6581    pub fn has_available_code_actions(&self) -> bool {
 6582        self.available_code_actions
 6583            .as_ref()
 6584            .is_some_and(|(_, actions)| !actions.is_empty())
 6585    }
 6586
 6587    fn render_inline_code_actions(
 6588        &self,
 6589        icon_size: ui::IconSize,
 6590        display_row: DisplayRow,
 6591        is_active: bool,
 6592        cx: &mut Context<Self>,
 6593    ) -> AnyElement {
 6594        let show_tooltip = !self.context_menu_visible();
 6595        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6596            .icon_size(icon_size)
 6597            .shape(ui::IconButtonShape::Square)
 6598            .icon_color(ui::Color::Hidden)
 6599            .toggle_state(is_active)
 6600            .when(show_tooltip, |this| {
 6601                this.tooltip({
 6602                    let focus_handle = self.focus_handle.clone();
 6603                    move |window, cx| {
 6604                        Tooltip::for_action_in(
 6605                            "Toggle Code Actions",
 6606                            &ToggleCodeActions {
 6607                                deployed_from: None,
 6608                                quick_launch: false,
 6609                            },
 6610                            &focus_handle,
 6611                            window,
 6612                            cx,
 6613                        )
 6614                    }
 6615                })
 6616            })
 6617            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6618                window.focus(&editor.focus_handle(cx));
 6619                editor.toggle_code_actions(
 6620                    &crate::actions::ToggleCodeActions {
 6621                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6622                            display_row,
 6623                        )),
 6624                        quick_launch: false,
 6625                    },
 6626                    window,
 6627                    cx,
 6628                );
 6629            }))
 6630            .into_any_element()
 6631    }
 6632
 6633    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6634        &self.context_menu
 6635    }
 6636
 6637    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6638        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6639            cx.background_executor()
 6640                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6641                .await;
 6642
 6643            let (start_buffer, start, _, end, newest_selection) = this
 6644                .update(cx, |this, cx| {
 6645                    let newest_selection = this.selections.newest_anchor().clone();
 6646                    if newest_selection.head().diff_base_anchor.is_some() {
 6647                        return None;
 6648                    }
 6649                    let display_snapshot = this.display_snapshot(cx);
 6650                    let newest_selection_adjusted =
 6651                        this.selections.newest_adjusted(&display_snapshot);
 6652                    let buffer = this.buffer.read(cx);
 6653
 6654                    let (start_buffer, start) =
 6655                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6656                    let (end_buffer, end) =
 6657                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6658
 6659                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6660                })?
 6661                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6662                .context(
 6663                    "Expected selection to lie in a single buffer when refreshing code actions",
 6664                )?;
 6665            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6666                let providers = this.code_action_providers.clone();
 6667                let tasks = this
 6668                    .code_action_providers
 6669                    .iter()
 6670                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6671                    .collect::<Vec<_>>();
 6672                (providers, tasks)
 6673            })?;
 6674
 6675            let mut actions = Vec::new();
 6676            for (provider, provider_actions) in
 6677                providers.into_iter().zip(future::join_all(tasks).await)
 6678            {
 6679                if let Some(provider_actions) = provider_actions.log_err() {
 6680                    actions.extend(provider_actions.into_iter().map(|action| {
 6681                        AvailableCodeAction {
 6682                            excerpt_id: newest_selection.start.excerpt_id,
 6683                            action,
 6684                            provider: provider.clone(),
 6685                        }
 6686                    }));
 6687                }
 6688            }
 6689
 6690            this.update(cx, |this, cx| {
 6691                this.available_code_actions = if actions.is_empty() {
 6692                    None
 6693                } else {
 6694                    Some((
 6695                        Location {
 6696                            buffer: start_buffer,
 6697                            range: start..end,
 6698                        },
 6699                        actions.into(),
 6700                    ))
 6701                };
 6702                cx.notify();
 6703            })
 6704        }));
 6705    }
 6706
 6707    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6708        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6709            self.show_git_blame_inline = false;
 6710
 6711            self.show_git_blame_inline_delay_task =
 6712                Some(cx.spawn_in(window, async move |this, cx| {
 6713                    cx.background_executor().timer(delay).await;
 6714
 6715                    this.update(cx, |this, cx| {
 6716                        this.show_git_blame_inline = true;
 6717                        cx.notify();
 6718                    })
 6719                    .log_err();
 6720                }));
 6721        }
 6722    }
 6723
 6724    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6725        let snapshot = self.snapshot(window, cx);
 6726        let cursor = self
 6727            .selections
 6728            .newest::<Point>(&snapshot.display_snapshot)
 6729            .head();
 6730        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6731        else {
 6732            return;
 6733        };
 6734
 6735        let Some(blame) = self.blame.as_ref() else {
 6736            return;
 6737        };
 6738
 6739        let row_info = RowInfo {
 6740            buffer_id: Some(buffer.remote_id()),
 6741            buffer_row: Some(point.row),
 6742            ..Default::default()
 6743        };
 6744        let Some((buffer, blame_entry)) = blame
 6745            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6746            .flatten()
 6747        else {
 6748            return;
 6749        };
 6750
 6751        let anchor = self.selections.newest_anchor().head();
 6752        let position = self.to_pixel_point(anchor, &snapshot, window);
 6753        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6754            self.show_blame_popover(
 6755                buffer,
 6756                &blame_entry,
 6757                position + last_bounds.origin,
 6758                true,
 6759                cx,
 6760            );
 6761        };
 6762    }
 6763
 6764    fn show_blame_popover(
 6765        &mut self,
 6766        buffer: BufferId,
 6767        blame_entry: &BlameEntry,
 6768        position: gpui::Point<Pixels>,
 6769        ignore_timeout: bool,
 6770        cx: &mut Context<Self>,
 6771    ) {
 6772        if let Some(state) = &mut self.inline_blame_popover {
 6773            state.hide_task.take();
 6774        } else {
 6775            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6776            let blame_entry = blame_entry.clone();
 6777            let show_task = cx.spawn(async move |editor, cx| {
 6778                if !ignore_timeout {
 6779                    cx.background_executor()
 6780                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6781                        .await;
 6782                }
 6783                editor
 6784                    .update(cx, |editor, cx| {
 6785                        editor.inline_blame_popover_show_task.take();
 6786                        let Some(blame) = editor.blame.as_ref() else {
 6787                            return;
 6788                        };
 6789                        let blame = blame.read(cx);
 6790                        let details = blame.details_for_entry(buffer, &blame_entry);
 6791                        let markdown = cx.new(|cx| {
 6792                            Markdown::new(
 6793                                details
 6794                                    .as_ref()
 6795                                    .map(|message| message.message.clone())
 6796                                    .unwrap_or_default(),
 6797                                None,
 6798                                None,
 6799                                cx,
 6800                            )
 6801                        });
 6802                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6803                            position,
 6804                            hide_task: None,
 6805                            popover_bounds: None,
 6806                            popover_state: InlineBlamePopoverState {
 6807                                scroll_handle: ScrollHandle::new(),
 6808                                commit_message: details,
 6809                                markdown,
 6810                            },
 6811                            keyboard_grace: ignore_timeout,
 6812                        });
 6813                        cx.notify();
 6814                    })
 6815                    .ok();
 6816            });
 6817            self.inline_blame_popover_show_task = Some(show_task);
 6818        }
 6819    }
 6820
 6821    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6822        self.inline_blame_popover_show_task.take();
 6823        if let Some(state) = &mut self.inline_blame_popover {
 6824            let hide_task = cx.spawn(async move |editor, cx| {
 6825                cx.background_executor()
 6826                    .timer(std::time::Duration::from_millis(100))
 6827                    .await;
 6828                editor
 6829                    .update(cx, |editor, cx| {
 6830                        editor.inline_blame_popover.take();
 6831                        cx.notify();
 6832                    })
 6833                    .ok();
 6834            });
 6835            state.hide_task = Some(hide_task);
 6836        }
 6837    }
 6838
 6839    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6840        if self.pending_rename.is_some() {
 6841            return None;
 6842        }
 6843
 6844        let provider = self.semantics_provider.clone()?;
 6845        let buffer = self.buffer.read(cx);
 6846        let newest_selection = self.selections.newest_anchor().clone();
 6847        let cursor_position = newest_selection.head();
 6848        let (cursor_buffer, cursor_buffer_position) =
 6849            buffer.text_anchor_for_position(cursor_position, cx)?;
 6850        let (tail_buffer, tail_buffer_position) =
 6851            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6852        if cursor_buffer != tail_buffer {
 6853            return None;
 6854        }
 6855
 6856        let snapshot = cursor_buffer.read(cx).snapshot();
 6857        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6858        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6859        if start_word_range != end_word_range {
 6860            self.document_highlights_task.take();
 6861            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6862            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6863            return None;
 6864        }
 6865
 6866        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6867        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6868            cx.background_executor()
 6869                .timer(Duration::from_millis(debounce))
 6870                .await;
 6871
 6872            let highlights = if let Some(highlights) = cx
 6873                .update(|cx| {
 6874                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6875                })
 6876                .ok()
 6877                .flatten()
 6878            {
 6879                highlights.await.log_err()
 6880            } else {
 6881                None
 6882            };
 6883
 6884            if let Some(highlights) = highlights {
 6885                this.update(cx, |this, cx| {
 6886                    if this.pending_rename.is_some() {
 6887                        return;
 6888                    }
 6889
 6890                    let buffer = this.buffer.read(cx);
 6891                    if buffer
 6892                        .text_anchor_for_position(cursor_position, cx)
 6893                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6894                    {
 6895                        return;
 6896                    }
 6897
 6898                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6899                    let mut write_ranges = Vec::new();
 6900                    let mut read_ranges = Vec::new();
 6901                    for highlight in highlights {
 6902                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6903                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6904                        {
 6905                            let start = highlight
 6906                                .range
 6907                                .start
 6908                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6909                            let end = highlight
 6910                                .range
 6911                                .end
 6912                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6913                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6914                                continue;
 6915                            }
 6916
 6917                            let range =
 6918                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6919                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6920                                write_ranges.push(range);
 6921                            } else {
 6922                                read_ranges.push(range);
 6923                            }
 6924                        }
 6925                    }
 6926
 6927                    this.highlight_background::<DocumentHighlightRead>(
 6928                        &read_ranges,
 6929                        |theme| theme.colors().editor_document_highlight_read_background,
 6930                        cx,
 6931                    );
 6932                    this.highlight_background::<DocumentHighlightWrite>(
 6933                        &write_ranges,
 6934                        |theme| theme.colors().editor_document_highlight_write_background,
 6935                        cx,
 6936                    );
 6937                    cx.notify();
 6938                })
 6939                .log_err();
 6940            }
 6941        }));
 6942        None
 6943    }
 6944
 6945    fn prepare_highlight_query_from_selection(
 6946        &mut self,
 6947        cx: &mut Context<Editor>,
 6948    ) -> Option<(String, Range<Anchor>)> {
 6949        if matches!(self.mode, EditorMode::SingleLine) {
 6950            return None;
 6951        }
 6952        if !EditorSettings::get_global(cx).selection_highlight {
 6953            return None;
 6954        }
 6955        if self.selections.count() != 1 || self.selections.line_mode() {
 6956            return None;
 6957        }
 6958        let selection = self.selections.newest_anchor();
 6959        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6960        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6961            ..selection.end.to_point(&multi_buffer_snapshot);
 6962        // If the selection spans multiple rows OR it is empty
 6963        if selection_point_range.start.row != selection_point_range.end.row
 6964            || selection_point_range.start.column == selection_point_range.end.column
 6965        {
 6966            return None;
 6967        }
 6968
 6969        let query = multi_buffer_snapshot
 6970            .text_for_range(selection.range())
 6971            .collect::<String>();
 6972        if query.trim().is_empty() {
 6973            return None;
 6974        }
 6975        Some((query, selection.range()))
 6976    }
 6977
 6978    fn update_selection_occurrence_highlights(
 6979        &mut self,
 6980        query_text: String,
 6981        query_range: Range<Anchor>,
 6982        multi_buffer_range_to_query: Range<Point>,
 6983        use_debounce: bool,
 6984        window: &mut Window,
 6985        cx: &mut Context<Editor>,
 6986    ) -> Task<()> {
 6987        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6988        cx.spawn_in(window, async move |editor, cx| {
 6989            if use_debounce {
 6990                cx.background_executor()
 6991                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6992                    .await;
 6993            }
 6994            let match_task = cx.background_spawn(async move {
 6995                let buffer_ranges = multi_buffer_snapshot
 6996                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6997                    .into_iter()
 6998                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6999                let mut match_ranges = Vec::new();
 7000                let Ok(regex) = project::search::SearchQuery::text(
 7001                    query_text.clone(),
 7002                    false,
 7003                    false,
 7004                    false,
 7005                    Default::default(),
 7006                    Default::default(),
 7007                    false,
 7008                    None,
 7009                ) else {
 7010                    return Vec::default();
 7011                };
 7012                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7013                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7014                    match_ranges.extend(
 7015                        regex
 7016                            .search(buffer_snapshot, Some(search_range.clone()))
 7017                            .await
 7018                            .into_iter()
 7019                            .filter_map(|match_range| {
 7020                                let match_start = buffer_snapshot
 7021                                    .anchor_after(search_range.start + match_range.start);
 7022                                let match_end = buffer_snapshot
 7023                                    .anchor_before(search_range.start + match_range.end);
 7024                                let match_anchor_range = Anchor::range_in_buffer(
 7025                                    excerpt_id,
 7026                                    buffer_snapshot.remote_id(),
 7027                                    match_start..match_end,
 7028                                );
 7029                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7030                            }),
 7031                    );
 7032                }
 7033                match_ranges
 7034            });
 7035            let match_ranges = match_task.await;
 7036            editor
 7037                .update_in(cx, |editor, _, cx| {
 7038                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7039                    if !match_ranges.is_empty() {
 7040                        editor.highlight_background::<SelectedTextHighlight>(
 7041                            &match_ranges,
 7042                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7043                            cx,
 7044                        )
 7045                    }
 7046                })
 7047                .log_err();
 7048        })
 7049    }
 7050
 7051    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7052        struct NewlineFold;
 7053        let type_id = std::any::TypeId::of::<NewlineFold>();
 7054        if !self.mode.is_single_line() {
 7055            return;
 7056        }
 7057        let snapshot = self.snapshot(window, cx);
 7058        if snapshot.buffer_snapshot().max_point().row == 0 {
 7059            return;
 7060        }
 7061        let task = cx.background_spawn(async move {
 7062            let new_newlines = snapshot
 7063                .buffer_chars_at(0)
 7064                .filter_map(|(c, i)| {
 7065                    if c == '\n' {
 7066                        Some(
 7067                            snapshot.buffer_snapshot().anchor_after(i)
 7068                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7069                        )
 7070                    } else {
 7071                        None
 7072                    }
 7073                })
 7074                .collect::<Vec<_>>();
 7075            let existing_newlines = snapshot
 7076                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7077                .filter_map(|fold| {
 7078                    if fold.placeholder.type_tag == Some(type_id) {
 7079                        Some(fold.range.start..fold.range.end)
 7080                    } else {
 7081                        None
 7082                    }
 7083                })
 7084                .collect::<Vec<_>>();
 7085
 7086            (new_newlines, existing_newlines)
 7087        });
 7088        self.folding_newlines = cx.spawn(async move |this, cx| {
 7089            let (new_newlines, existing_newlines) = task.await;
 7090            if new_newlines == existing_newlines {
 7091                return;
 7092            }
 7093            let placeholder = FoldPlaceholder {
 7094                render: Arc::new(move |_, _, cx| {
 7095                    div()
 7096                        .bg(cx.theme().status().hint_background)
 7097                        .border_b_1()
 7098                        .size_full()
 7099                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7100                        .border_color(cx.theme().status().hint)
 7101                        .child("\\n")
 7102                        .into_any()
 7103                }),
 7104                constrain_width: false,
 7105                merge_adjacent: false,
 7106                type_tag: Some(type_id),
 7107            };
 7108            let creases = new_newlines
 7109                .into_iter()
 7110                .map(|range| Crease::simple(range, placeholder.clone()))
 7111                .collect();
 7112            this.update(cx, |this, cx| {
 7113                this.display_map.update(cx, |display_map, cx| {
 7114                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7115                    display_map.fold(creases, cx);
 7116                });
 7117            })
 7118            .ok();
 7119        });
 7120    }
 7121
 7122    fn refresh_selected_text_highlights(
 7123        &mut self,
 7124        on_buffer_edit: bool,
 7125        window: &mut Window,
 7126        cx: &mut Context<Editor>,
 7127    ) {
 7128        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7129        else {
 7130            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7131            self.quick_selection_highlight_task.take();
 7132            self.debounced_selection_highlight_task.take();
 7133            return;
 7134        };
 7135        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7136        if on_buffer_edit
 7137            || self
 7138                .quick_selection_highlight_task
 7139                .as_ref()
 7140                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7141        {
 7142            let multi_buffer_visible_start = self
 7143                .scroll_manager
 7144                .anchor()
 7145                .anchor
 7146                .to_point(&multi_buffer_snapshot);
 7147            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7148                multi_buffer_visible_start
 7149                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7150                Bias::Left,
 7151            );
 7152            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7153            self.quick_selection_highlight_task = Some((
 7154                query_range.clone(),
 7155                self.update_selection_occurrence_highlights(
 7156                    query_text.clone(),
 7157                    query_range.clone(),
 7158                    multi_buffer_visible_range,
 7159                    false,
 7160                    window,
 7161                    cx,
 7162                ),
 7163            ));
 7164        }
 7165        if on_buffer_edit
 7166            || self
 7167                .debounced_selection_highlight_task
 7168                .as_ref()
 7169                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7170        {
 7171            let multi_buffer_start = multi_buffer_snapshot
 7172                .anchor_before(0)
 7173                .to_point(&multi_buffer_snapshot);
 7174            let multi_buffer_end = multi_buffer_snapshot
 7175                .anchor_after(multi_buffer_snapshot.len())
 7176                .to_point(&multi_buffer_snapshot);
 7177            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7178            self.debounced_selection_highlight_task = Some((
 7179                query_range.clone(),
 7180                self.update_selection_occurrence_highlights(
 7181                    query_text,
 7182                    query_range,
 7183                    multi_buffer_full_range,
 7184                    true,
 7185                    window,
 7186                    cx,
 7187                ),
 7188            ));
 7189        }
 7190    }
 7191
 7192    pub fn refresh_edit_prediction(
 7193        &mut self,
 7194        debounce: bool,
 7195        user_requested: bool,
 7196        window: &mut Window,
 7197        cx: &mut Context<Self>,
 7198    ) -> Option<()> {
 7199        if DisableAiSettings::get_global(cx).disable_ai {
 7200            return None;
 7201        }
 7202
 7203        let provider = self.edit_prediction_provider()?;
 7204        let cursor = self.selections.newest_anchor().head();
 7205        let (buffer, cursor_buffer_position) =
 7206            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7207
 7208        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7209            self.discard_edit_prediction(false, cx);
 7210            return None;
 7211        }
 7212
 7213        self.update_visible_edit_prediction(window, cx);
 7214
 7215        if !user_requested
 7216            && (!self.should_show_edit_predictions()
 7217                || !self.is_focused(window)
 7218                || buffer.read(cx).is_empty())
 7219        {
 7220            self.discard_edit_prediction(false, cx);
 7221            return None;
 7222        }
 7223
 7224        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7225        Some(())
 7226    }
 7227
 7228    fn show_edit_predictions_in_menu(&self) -> bool {
 7229        match self.edit_prediction_settings {
 7230            EditPredictionSettings::Disabled => false,
 7231            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7232        }
 7233    }
 7234
 7235    pub fn edit_predictions_enabled(&self) -> bool {
 7236        match self.edit_prediction_settings {
 7237            EditPredictionSettings::Disabled => false,
 7238            EditPredictionSettings::Enabled { .. } => true,
 7239        }
 7240    }
 7241
 7242    fn edit_prediction_requires_modifier(&self) -> bool {
 7243        match self.edit_prediction_settings {
 7244            EditPredictionSettings::Disabled => false,
 7245            EditPredictionSettings::Enabled {
 7246                preview_requires_modifier,
 7247                ..
 7248            } => preview_requires_modifier,
 7249        }
 7250    }
 7251
 7252    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7253        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7254            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7255            self.discard_edit_prediction(false, cx);
 7256        } else {
 7257            let selection = self.selections.newest_anchor();
 7258            let cursor = selection.head();
 7259
 7260            if let Some((buffer, cursor_buffer_position)) =
 7261                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7262            {
 7263                self.edit_prediction_settings =
 7264                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7265            }
 7266        }
 7267    }
 7268
 7269    fn edit_prediction_settings_at_position(
 7270        &self,
 7271        buffer: &Entity<Buffer>,
 7272        buffer_position: language::Anchor,
 7273        cx: &App,
 7274    ) -> EditPredictionSettings {
 7275        if !self.mode.is_full()
 7276            || !self.show_edit_predictions_override.unwrap_or(true)
 7277            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7278        {
 7279            return EditPredictionSettings::Disabled;
 7280        }
 7281
 7282        let buffer = buffer.read(cx);
 7283
 7284        let file = buffer.file();
 7285
 7286        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7287            return EditPredictionSettings::Disabled;
 7288        };
 7289
 7290        let by_provider = matches!(
 7291            self.menu_edit_predictions_policy,
 7292            MenuEditPredictionsPolicy::ByProvider
 7293        );
 7294
 7295        let show_in_menu = by_provider
 7296            && self
 7297                .edit_prediction_provider
 7298                .as_ref()
 7299                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7300
 7301        let preview_requires_modifier =
 7302            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7303
 7304        EditPredictionSettings::Enabled {
 7305            show_in_menu,
 7306            preview_requires_modifier,
 7307        }
 7308    }
 7309
 7310    fn should_show_edit_predictions(&self) -> bool {
 7311        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7312    }
 7313
 7314    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7315        matches!(
 7316            self.edit_prediction_preview,
 7317            EditPredictionPreview::Active { .. }
 7318        )
 7319    }
 7320
 7321    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7322        let cursor = self.selections.newest_anchor().head();
 7323        if let Some((buffer, cursor_position)) =
 7324            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7325        {
 7326            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7327        } else {
 7328            false
 7329        }
 7330    }
 7331
 7332    pub fn supports_minimap(&self, cx: &App) -> bool {
 7333        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7334    }
 7335
 7336    fn edit_predictions_enabled_in_buffer(
 7337        &self,
 7338        buffer: &Entity<Buffer>,
 7339        buffer_position: language::Anchor,
 7340        cx: &App,
 7341    ) -> bool {
 7342        maybe!({
 7343            if self.read_only(cx) {
 7344                return Some(false);
 7345            }
 7346            let provider = self.edit_prediction_provider()?;
 7347            if !provider.is_enabled(buffer, buffer_position, cx) {
 7348                return Some(false);
 7349            }
 7350            let buffer = buffer.read(cx);
 7351            let Some(file) = buffer.file() else {
 7352                return Some(true);
 7353            };
 7354            let settings = all_language_settings(Some(file), cx);
 7355            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7356        })
 7357        .unwrap_or(false)
 7358    }
 7359
 7360    fn cycle_edit_prediction(
 7361        &mut self,
 7362        direction: Direction,
 7363        window: &mut Window,
 7364        cx: &mut Context<Self>,
 7365    ) -> Option<()> {
 7366        let provider = self.edit_prediction_provider()?;
 7367        let cursor = self.selections.newest_anchor().head();
 7368        let (buffer, cursor_buffer_position) =
 7369            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7370        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7371            return None;
 7372        }
 7373
 7374        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7375        self.update_visible_edit_prediction(window, cx);
 7376
 7377        Some(())
 7378    }
 7379
 7380    pub fn show_edit_prediction(
 7381        &mut self,
 7382        _: &ShowEditPrediction,
 7383        window: &mut Window,
 7384        cx: &mut Context<Self>,
 7385    ) {
 7386        if !self.has_active_edit_prediction() {
 7387            self.refresh_edit_prediction(false, true, window, cx);
 7388            return;
 7389        }
 7390
 7391        self.update_visible_edit_prediction(window, cx);
 7392    }
 7393
 7394    pub fn display_cursor_names(
 7395        &mut self,
 7396        _: &DisplayCursorNames,
 7397        window: &mut Window,
 7398        cx: &mut Context<Self>,
 7399    ) {
 7400        self.show_cursor_names(window, cx);
 7401    }
 7402
 7403    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7404        self.show_cursor_names = true;
 7405        cx.notify();
 7406        cx.spawn_in(window, async move |this, cx| {
 7407            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7408            this.update(cx, |this, cx| {
 7409                this.show_cursor_names = false;
 7410                cx.notify()
 7411            })
 7412            .ok()
 7413        })
 7414        .detach();
 7415    }
 7416
 7417    pub fn next_edit_prediction(
 7418        &mut self,
 7419        _: &NextEditPrediction,
 7420        window: &mut Window,
 7421        cx: &mut Context<Self>,
 7422    ) {
 7423        if self.has_active_edit_prediction() {
 7424            self.cycle_edit_prediction(Direction::Next, window, cx);
 7425        } else {
 7426            let is_copilot_disabled = self
 7427                .refresh_edit_prediction(false, true, window, cx)
 7428                .is_none();
 7429            if is_copilot_disabled {
 7430                cx.propagate();
 7431            }
 7432        }
 7433    }
 7434
 7435    pub fn previous_edit_prediction(
 7436        &mut self,
 7437        _: &PreviousEditPrediction,
 7438        window: &mut Window,
 7439        cx: &mut Context<Self>,
 7440    ) {
 7441        if self.has_active_edit_prediction() {
 7442            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7443        } else {
 7444            let is_copilot_disabled = self
 7445                .refresh_edit_prediction(false, true, window, cx)
 7446                .is_none();
 7447            if is_copilot_disabled {
 7448                cx.propagate();
 7449            }
 7450        }
 7451    }
 7452
 7453    pub fn accept_edit_prediction(
 7454        &mut self,
 7455        _: &AcceptEditPrediction,
 7456        window: &mut Window,
 7457        cx: &mut Context<Self>,
 7458    ) {
 7459        if self.show_edit_predictions_in_menu() {
 7460            self.hide_context_menu(window, cx);
 7461        }
 7462
 7463        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7464            return;
 7465        };
 7466
 7467        match &active_edit_prediction.completion {
 7468            EditPrediction::MoveWithin { target, .. } => {
 7469                let target = *target;
 7470
 7471                if let Some(position_map) = &self.last_position_map {
 7472                    if position_map
 7473                        .visible_row_range
 7474                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7475                        || !self.edit_prediction_requires_modifier()
 7476                    {
 7477                        self.unfold_ranges(&[target..target], true, false, cx);
 7478                        // Note that this is also done in vim's handler of the Tab action.
 7479                        self.change_selections(
 7480                            SelectionEffects::scroll(Autoscroll::newest()),
 7481                            window,
 7482                            cx,
 7483                            |selections| {
 7484                                selections.select_anchor_ranges([target..target]);
 7485                            },
 7486                        );
 7487                        self.clear_row_highlights::<EditPredictionPreview>();
 7488
 7489                        self.edit_prediction_preview
 7490                            .set_previous_scroll_position(None);
 7491                    } else {
 7492                        self.edit_prediction_preview
 7493                            .set_previous_scroll_position(Some(
 7494                                position_map.snapshot.scroll_anchor,
 7495                            ));
 7496
 7497                        self.highlight_rows::<EditPredictionPreview>(
 7498                            target..target,
 7499                            cx.theme().colors().editor_highlighted_line_background,
 7500                            RowHighlightOptions {
 7501                                autoscroll: true,
 7502                                ..Default::default()
 7503                            },
 7504                            cx,
 7505                        );
 7506                        self.request_autoscroll(Autoscroll::fit(), cx);
 7507                    }
 7508                }
 7509            }
 7510            EditPrediction::MoveOutside { snapshot, target } => {
 7511                if let Some(workspace) = self.workspace() {
 7512                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7513                        .detach_and_log_err(cx);
 7514                }
 7515            }
 7516            EditPrediction::Edit { edits, .. } => {
 7517                self.report_edit_prediction_event(
 7518                    active_edit_prediction.completion_id.clone(),
 7519                    true,
 7520                    cx,
 7521                );
 7522
 7523                if let Some(provider) = self.edit_prediction_provider() {
 7524                    provider.accept(cx);
 7525                }
 7526
 7527                // Store the transaction ID and selections before applying the edit
 7528                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7529
 7530                let snapshot = self.buffer.read(cx).snapshot(cx);
 7531                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7532
 7533                self.buffer.update(cx, |buffer, cx| {
 7534                    buffer.edit(edits.iter().cloned(), None, cx)
 7535                });
 7536
 7537                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7538                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7539                });
 7540
 7541                let selections = self.selections.disjoint_anchors_arc();
 7542                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7543                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7544                    if has_new_transaction {
 7545                        self.selection_history
 7546                            .insert_transaction(transaction_id_now, selections);
 7547                    }
 7548                }
 7549
 7550                self.update_visible_edit_prediction(window, cx);
 7551                if self.active_edit_prediction.is_none() {
 7552                    self.refresh_edit_prediction(true, true, window, cx);
 7553                }
 7554
 7555                cx.notify();
 7556            }
 7557        }
 7558
 7559        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7560    }
 7561
 7562    pub fn accept_partial_edit_prediction(
 7563        &mut self,
 7564        _: &AcceptPartialEditPrediction,
 7565        window: &mut Window,
 7566        cx: &mut Context<Self>,
 7567    ) {
 7568        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7569            return;
 7570        };
 7571        if self.selections.count() != 1 {
 7572            return;
 7573        }
 7574
 7575        match &active_edit_prediction.completion {
 7576            EditPrediction::MoveWithin { target, .. } => {
 7577                let target = *target;
 7578                self.change_selections(
 7579                    SelectionEffects::scroll(Autoscroll::newest()),
 7580                    window,
 7581                    cx,
 7582                    |selections| {
 7583                        selections.select_anchor_ranges([target..target]);
 7584                    },
 7585                );
 7586            }
 7587            EditPrediction::MoveOutside { snapshot, target } => {
 7588                if let Some(workspace) = self.workspace() {
 7589                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7590                        .detach_and_log_err(cx);
 7591                }
 7592            }
 7593            EditPrediction::Edit { edits, .. } => {
 7594                self.report_edit_prediction_event(
 7595                    active_edit_prediction.completion_id.clone(),
 7596                    true,
 7597                    cx,
 7598                );
 7599
 7600                // Find an insertion that starts at the cursor position.
 7601                let snapshot = self.buffer.read(cx).snapshot(cx);
 7602                let cursor_offset = self
 7603                    .selections
 7604                    .newest::<usize>(&self.display_snapshot(cx))
 7605                    .head();
 7606                let insertion = edits.iter().find_map(|(range, text)| {
 7607                    let range = range.to_offset(&snapshot);
 7608                    if range.is_empty() && range.start == cursor_offset {
 7609                        Some(text)
 7610                    } else {
 7611                        None
 7612                    }
 7613                });
 7614
 7615                if let Some(text) = insertion {
 7616                    let mut partial_completion = text
 7617                        .chars()
 7618                        .by_ref()
 7619                        .take_while(|c| c.is_alphabetic())
 7620                        .collect::<String>();
 7621                    if partial_completion.is_empty() {
 7622                        partial_completion = text
 7623                            .chars()
 7624                            .by_ref()
 7625                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7626                            .collect::<String>();
 7627                    }
 7628
 7629                    cx.emit(EditorEvent::InputHandled {
 7630                        utf16_range_to_replace: None,
 7631                        text: partial_completion.clone().into(),
 7632                    });
 7633
 7634                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7635
 7636                    self.refresh_edit_prediction(true, true, window, cx);
 7637                    cx.notify();
 7638                } else {
 7639                    self.accept_edit_prediction(&Default::default(), window, cx);
 7640                }
 7641            }
 7642        }
 7643    }
 7644
 7645    fn discard_edit_prediction(
 7646        &mut self,
 7647        should_report_edit_prediction_event: bool,
 7648        cx: &mut Context<Self>,
 7649    ) -> bool {
 7650        if should_report_edit_prediction_event {
 7651            let completion_id = self
 7652                .active_edit_prediction
 7653                .as_ref()
 7654                .and_then(|active_completion| active_completion.completion_id.clone());
 7655
 7656            self.report_edit_prediction_event(completion_id, false, cx);
 7657        }
 7658
 7659        if let Some(provider) = self.edit_prediction_provider() {
 7660            provider.discard(cx);
 7661        }
 7662
 7663        self.take_active_edit_prediction(cx)
 7664    }
 7665
 7666    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7667        let Some(provider) = self.edit_prediction_provider() else {
 7668            return;
 7669        };
 7670
 7671        let Some((_, buffer, _)) = self
 7672            .buffer
 7673            .read(cx)
 7674            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7675        else {
 7676            return;
 7677        };
 7678
 7679        let extension = buffer
 7680            .read(cx)
 7681            .file()
 7682            .and_then(|file| Some(file.path().extension()?.to_string()));
 7683
 7684        let event_type = match accepted {
 7685            true => "Edit Prediction Accepted",
 7686            false => "Edit Prediction Discarded",
 7687        };
 7688        telemetry::event!(
 7689            event_type,
 7690            provider = provider.name(),
 7691            prediction_id = id,
 7692            suggestion_accepted = accepted,
 7693            file_extension = extension,
 7694        );
 7695    }
 7696
 7697    fn open_editor_at_anchor(
 7698        snapshot: &language::BufferSnapshot,
 7699        target: language::Anchor,
 7700        workspace: &Entity<Workspace>,
 7701        window: &mut Window,
 7702        cx: &mut App,
 7703    ) -> Task<Result<()>> {
 7704        workspace.update(cx, |workspace, cx| {
 7705            let path = snapshot.file().map(|file| file.full_path(cx));
 7706            let Some(path) =
 7707                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7708            else {
 7709                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7710            };
 7711            let target = text::ToPoint::to_point(&target, snapshot);
 7712            let item = workspace.open_path(path, None, true, window, cx);
 7713            window.spawn(cx, async move |cx| {
 7714                let Some(editor) = item.await?.downcast::<Editor>() else {
 7715                    return Ok(());
 7716                };
 7717                editor
 7718                    .update_in(cx, |editor, window, cx| {
 7719                        editor.go_to_singleton_buffer_point(target, window, cx);
 7720                    })
 7721                    .ok();
 7722                anyhow::Ok(())
 7723            })
 7724        })
 7725    }
 7726
 7727    pub fn has_active_edit_prediction(&self) -> bool {
 7728        self.active_edit_prediction.is_some()
 7729    }
 7730
 7731    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7732        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7733            return false;
 7734        };
 7735
 7736        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7737        self.clear_highlights::<EditPredictionHighlight>(cx);
 7738        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7739        true
 7740    }
 7741
 7742    /// Returns true when we're displaying the edit prediction popover below the cursor
 7743    /// like we are not previewing and the LSP autocomplete menu is visible
 7744    /// or we are in `when_holding_modifier` mode.
 7745    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7746        if self.edit_prediction_preview_is_active()
 7747            || !self.show_edit_predictions_in_menu()
 7748            || !self.edit_predictions_enabled()
 7749        {
 7750            return false;
 7751        }
 7752
 7753        if self.has_visible_completions_menu() {
 7754            return true;
 7755        }
 7756
 7757        has_completion && self.edit_prediction_requires_modifier()
 7758    }
 7759
 7760    fn handle_modifiers_changed(
 7761        &mut self,
 7762        modifiers: Modifiers,
 7763        position_map: &PositionMap,
 7764        window: &mut Window,
 7765        cx: &mut Context<Self>,
 7766    ) {
 7767        if self.show_edit_predictions_in_menu() {
 7768            self.update_edit_prediction_preview(&modifiers, window, cx);
 7769        }
 7770
 7771        self.update_selection_mode(&modifiers, position_map, window, cx);
 7772
 7773        let mouse_position = window.mouse_position();
 7774        if !position_map.text_hitbox.is_hovered(window) {
 7775            return;
 7776        }
 7777
 7778        self.update_hovered_link(
 7779            position_map.point_for_position(mouse_position),
 7780            &position_map.snapshot,
 7781            modifiers,
 7782            window,
 7783            cx,
 7784        )
 7785    }
 7786
 7787    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7788        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7789        if invert {
 7790            match multi_cursor_setting {
 7791                MultiCursorModifier::Alt => modifiers.alt,
 7792                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7793            }
 7794        } else {
 7795            match multi_cursor_setting {
 7796                MultiCursorModifier::Alt => modifiers.secondary(),
 7797                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7798            }
 7799        }
 7800    }
 7801
 7802    fn columnar_selection_mode(
 7803        modifiers: &Modifiers,
 7804        cx: &mut Context<Self>,
 7805    ) -> Option<ColumnarMode> {
 7806        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7807            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7808                Some(ColumnarMode::FromMouse)
 7809            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7810                Some(ColumnarMode::FromSelection)
 7811            } else {
 7812                None
 7813            }
 7814        } else {
 7815            None
 7816        }
 7817    }
 7818
 7819    fn update_selection_mode(
 7820        &mut self,
 7821        modifiers: &Modifiers,
 7822        position_map: &PositionMap,
 7823        window: &mut Window,
 7824        cx: &mut Context<Self>,
 7825    ) {
 7826        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7827            return;
 7828        };
 7829        if self.selections.pending_anchor().is_none() {
 7830            return;
 7831        }
 7832
 7833        let mouse_position = window.mouse_position();
 7834        let point_for_position = position_map.point_for_position(mouse_position);
 7835        let position = point_for_position.previous_valid;
 7836
 7837        self.select(
 7838            SelectPhase::BeginColumnar {
 7839                position,
 7840                reset: false,
 7841                mode,
 7842                goal_column: point_for_position.exact_unclipped.column(),
 7843            },
 7844            window,
 7845            cx,
 7846        );
 7847    }
 7848
 7849    fn update_edit_prediction_preview(
 7850        &mut self,
 7851        modifiers: &Modifiers,
 7852        window: &mut Window,
 7853        cx: &mut Context<Self>,
 7854    ) {
 7855        let mut modifiers_held = false;
 7856        if let Some(accept_keystroke) = self
 7857            .accept_edit_prediction_keybind(false, window, cx)
 7858            .keystroke()
 7859        {
 7860            modifiers_held = modifiers_held
 7861                || (accept_keystroke.modifiers() == modifiers
 7862                    && accept_keystroke.modifiers().modified());
 7863        };
 7864        if let Some(accept_partial_keystroke) = self
 7865            .accept_edit_prediction_keybind(true, window, cx)
 7866            .keystroke()
 7867        {
 7868            modifiers_held = modifiers_held
 7869                || (accept_partial_keystroke.modifiers() == modifiers
 7870                    && accept_partial_keystroke.modifiers().modified());
 7871        }
 7872
 7873        if modifiers_held {
 7874            if matches!(
 7875                self.edit_prediction_preview,
 7876                EditPredictionPreview::Inactive { .. }
 7877            ) {
 7878                self.edit_prediction_preview = EditPredictionPreview::Active {
 7879                    previous_scroll_position: None,
 7880                    since: Instant::now(),
 7881                };
 7882
 7883                self.update_visible_edit_prediction(window, cx);
 7884                cx.notify();
 7885            }
 7886        } else if let EditPredictionPreview::Active {
 7887            previous_scroll_position,
 7888            since,
 7889        } = self.edit_prediction_preview
 7890        {
 7891            if let (Some(previous_scroll_position), Some(position_map)) =
 7892                (previous_scroll_position, self.last_position_map.as_ref())
 7893            {
 7894                self.set_scroll_position(
 7895                    previous_scroll_position
 7896                        .scroll_position(&position_map.snapshot.display_snapshot),
 7897                    window,
 7898                    cx,
 7899                );
 7900            }
 7901
 7902            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7903                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7904            };
 7905            self.clear_row_highlights::<EditPredictionPreview>();
 7906            self.update_visible_edit_prediction(window, cx);
 7907            cx.notify();
 7908        }
 7909    }
 7910
 7911    fn update_visible_edit_prediction(
 7912        &mut self,
 7913        _window: &mut Window,
 7914        cx: &mut Context<Self>,
 7915    ) -> Option<()> {
 7916        if DisableAiSettings::get_global(cx).disable_ai {
 7917            return None;
 7918        }
 7919
 7920        if self.ime_transaction.is_some() {
 7921            self.discard_edit_prediction(false, cx);
 7922            return None;
 7923        }
 7924
 7925        let selection = self.selections.newest_anchor();
 7926        let cursor = selection.head();
 7927        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7928        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7929        let excerpt_id = cursor.excerpt_id;
 7930
 7931        let show_in_menu = self.show_edit_predictions_in_menu();
 7932        let completions_menu_has_precedence = !show_in_menu
 7933            && (self.context_menu.borrow().is_some()
 7934                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7935
 7936        if completions_menu_has_precedence
 7937            || !offset_selection.is_empty()
 7938            || self
 7939                .active_edit_prediction
 7940                .as_ref()
 7941                .is_some_and(|completion| {
 7942                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7943                        return false;
 7944                    };
 7945                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7946                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7947                    !invalidation_range.contains(&offset_selection.head())
 7948                })
 7949        {
 7950            self.discard_edit_prediction(false, cx);
 7951            return None;
 7952        }
 7953
 7954        self.take_active_edit_prediction(cx);
 7955        let Some(provider) = self.edit_prediction_provider() else {
 7956            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7957            return None;
 7958        };
 7959
 7960        let (buffer, cursor_buffer_position) =
 7961            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7962
 7963        self.edit_prediction_settings =
 7964            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7965
 7966        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7967
 7968        if self.edit_prediction_indent_conflict {
 7969            let cursor_point = cursor.to_point(&multibuffer);
 7970
 7971            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7972
 7973            if let Some((_, indent)) = indents.iter().next()
 7974                && indent.len == cursor_point.column
 7975            {
 7976                self.edit_prediction_indent_conflict = false;
 7977            }
 7978        }
 7979
 7980        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7981
 7982        let (completion_id, edits, edit_preview) = match edit_prediction {
 7983            edit_prediction::EditPrediction::Local {
 7984                id,
 7985                edits,
 7986                edit_preview,
 7987            } => (id, edits, edit_preview),
 7988            edit_prediction::EditPrediction::Jump {
 7989                id,
 7990                snapshot,
 7991                target,
 7992            } => {
 7993                self.stale_edit_prediction_in_menu = None;
 7994                self.active_edit_prediction = Some(EditPredictionState {
 7995                    inlay_ids: vec![],
 7996                    completion: EditPrediction::MoveOutside { snapshot, target },
 7997                    completion_id: id,
 7998                    invalidation_range: None,
 7999                });
 8000                cx.notify();
 8001                return Some(());
 8002            }
 8003        };
 8004
 8005        let edits = edits
 8006            .into_iter()
 8007            .flat_map(|(range, new_text)| {
 8008                Some((
 8009                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8010                    new_text,
 8011                ))
 8012            })
 8013            .collect::<Vec<_>>();
 8014        if edits.is_empty() {
 8015            return None;
 8016        }
 8017
 8018        let first_edit_start = edits.first().unwrap().0.start;
 8019        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8020        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8021
 8022        let last_edit_end = edits.last().unwrap().0.end;
 8023        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8024        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8025
 8026        let cursor_row = cursor.to_point(&multibuffer).row;
 8027
 8028        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8029
 8030        let mut inlay_ids = Vec::new();
 8031        let invalidation_row_range;
 8032        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8033            Some(cursor_row..edit_end_row)
 8034        } else if cursor_row > edit_end_row {
 8035            Some(edit_start_row..cursor_row)
 8036        } else {
 8037            None
 8038        };
 8039        let supports_jump = self
 8040            .edit_prediction_provider
 8041            .as_ref()
 8042            .map(|provider| provider.provider.supports_jump_to_edit())
 8043            .unwrap_or(true);
 8044
 8045        let is_move = supports_jump
 8046            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8047        let completion = if is_move {
 8048            invalidation_row_range =
 8049                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8050            let target = first_edit_start;
 8051            EditPrediction::MoveWithin { target, snapshot }
 8052        } else {
 8053            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8054                && !self.edit_predictions_hidden_for_vim_mode;
 8055
 8056            if show_completions_in_buffer {
 8057                if edits
 8058                    .iter()
 8059                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8060                {
 8061                    let mut inlays = Vec::new();
 8062                    for (range, new_text) in &edits {
 8063                        let inlay = Inlay::edit_prediction(
 8064                            post_inc(&mut self.next_inlay_id),
 8065                            range.start,
 8066                            new_text.as_str(),
 8067                        );
 8068                        inlay_ids.push(inlay.id);
 8069                        inlays.push(inlay);
 8070                    }
 8071
 8072                    self.splice_inlays(&[], inlays, cx);
 8073                } else {
 8074                    let background_color = cx.theme().status().deleted_background;
 8075                    self.highlight_text::<EditPredictionHighlight>(
 8076                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8077                        HighlightStyle {
 8078                            background_color: Some(background_color),
 8079                            ..Default::default()
 8080                        },
 8081                        cx,
 8082                    );
 8083                }
 8084            }
 8085
 8086            invalidation_row_range = edit_start_row..edit_end_row;
 8087
 8088            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8089                if provider.show_tab_accept_marker() {
 8090                    EditDisplayMode::TabAccept
 8091                } else {
 8092                    EditDisplayMode::Inline
 8093                }
 8094            } else {
 8095                EditDisplayMode::DiffPopover
 8096            };
 8097
 8098            EditPrediction::Edit {
 8099                edits,
 8100                edit_preview,
 8101                display_mode,
 8102                snapshot,
 8103            }
 8104        };
 8105
 8106        let invalidation_range = multibuffer
 8107            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8108            ..multibuffer.anchor_after(Point::new(
 8109                invalidation_row_range.end,
 8110                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8111            ));
 8112
 8113        self.stale_edit_prediction_in_menu = None;
 8114        self.active_edit_prediction = Some(EditPredictionState {
 8115            inlay_ids,
 8116            completion,
 8117            completion_id,
 8118            invalidation_range: Some(invalidation_range),
 8119        });
 8120
 8121        cx.notify();
 8122
 8123        Some(())
 8124    }
 8125
 8126    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8127        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8128    }
 8129
 8130    fn clear_tasks(&mut self) {
 8131        self.tasks.clear()
 8132    }
 8133
 8134    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8135        if self.tasks.insert(key, value).is_some() {
 8136            // This case should hopefully be rare, but just in case...
 8137            log::error!(
 8138                "multiple different run targets found on a single line, only the last target will be rendered"
 8139            )
 8140        }
 8141    }
 8142
 8143    /// Get all display points of breakpoints that will be rendered within editor
 8144    ///
 8145    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8146    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8147    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8148    fn active_breakpoints(
 8149        &self,
 8150        range: Range<DisplayRow>,
 8151        window: &mut Window,
 8152        cx: &mut Context<Self>,
 8153    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8154        let mut breakpoint_display_points = HashMap::default();
 8155
 8156        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8157            return breakpoint_display_points;
 8158        };
 8159
 8160        let snapshot = self.snapshot(window, cx);
 8161
 8162        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8163        let Some(project) = self.project() else {
 8164            return breakpoint_display_points;
 8165        };
 8166
 8167        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8168            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8169
 8170        for (buffer_snapshot, range, excerpt_id) in
 8171            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8172        {
 8173            let Some(buffer) = project
 8174                .read(cx)
 8175                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8176            else {
 8177                continue;
 8178            };
 8179            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8180                &buffer,
 8181                Some(
 8182                    buffer_snapshot.anchor_before(range.start)
 8183                        ..buffer_snapshot.anchor_after(range.end),
 8184                ),
 8185                buffer_snapshot,
 8186                cx,
 8187            );
 8188            for (breakpoint, state) in breakpoints {
 8189                let multi_buffer_anchor =
 8190                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8191                let position = multi_buffer_anchor
 8192                    .to_point(multi_buffer_snapshot)
 8193                    .to_display_point(&snapshot);
 8194
 8195                breakpoint_display_points.insert(
 8196                    position.row(),
 8197                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8198                );
 8199            }
 8200        }
 8201
 8202        breakpoint_display_points
 8203    }
 8204
 8205    fn breakpoint_context_menu(
 8206        &self,
 8207        anchor: Anchor,
 8208        window: &mut Window,
 8209        cx: &mut Context<Self>,
 8210    ) -> Entity<ui::ContextMenu> {
 8211        let weak_editor = cx.weak_entity();
 8212        let focus_handle = self.focus_handle(cx);
 8213
 8214        let row = self
 8215            .buffer
 8216            .read(cx)
 8217            .snapshot(cx)
 8218            .summary_for_anchor::<Point>(&anchor)
 8219            .row;
 8220
 8221        let breakpoint = self
 8222            .breakpoint_at_row(row, window, cx)
 8223            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8224
 8225        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8226            "Edit Log Breakpoint"
 8227        } else {
 8228            "Set Log Breakpoint"
 8229        };
 8230
 8231        let condition_breakpoint_msg = if breakpoint
 8232            .as_ref()
 8233            .is_some_and(|bp| bp.1.condition.is_some())
 8234        {
 8235            "Edit Condition Breakpoint"
 8236        } else {
 8237            "Set Condition Breakpoint"
 8238        };
 8239
 8240        let hit_condition_breakpoint_msg = if breakpoint
 8241            .as_ref()
 8242            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8243        {
 8244            "Edit Hit Condition Breakpoint"
 8245        } else {
 8246            "Set Hit Condition Breakpoint"
 8247        };
 8248
 8249        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8250            "Unset Breakpoint"
 8251        } else {
 8252            "Set Breakpoint"
 8253        };
 8254
 8255        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8256
 8257        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8258            BreakpointState::Enabled => Some("Disable"),
 8259            BreakpointState::Disabled => Some("Enable"),
 8260        });
 8261
 8262        let (anchor, breakpoint) =
 8263            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8264
 8265        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8266            menu.on_blur_subscription(Subscription::new(|| {}))
 8267                .context(focus_handle)
 8268                .when(run_to_cursor, |this| {
 8269                    let weak_editor = weak_editor.clone();
 8270                    this.entry("Run to cursor", None, move |window, cx| {
 8271                        weak_editor
 8272                            .update(cx, |editor, cx| {
 8273                                editor.change_selections(
 8274                                    SelectionEffects::no_scroll(),
 8275                                    window,
 8276                                    cx,
 8277                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8278                                );
 8279                            })
 8280                            .ok();
 8281
 8282                        window.dispatch_action(Box::new(RunToCursor), cx);
 8283                    })
 8284                    .separator()
 8285                })
 8286                .when_some(toggle_state_msg, |this, msg| {
 8287                    this.entry(msg, None, {
 8288                        let weak_editor = weak_editor.clone();
 8289                        let breakpoint = breakpoint.clone();
 8290                        move |_window, cx| {
 8291                            weak_editor
 8292                                .update(cx, |this, cx| {
 8293                                    this.edit_breakpoint_at_anchor(
 8294                                        anchor,
 8295                                        breakpoint.as_ref().clone(),
 8296                                        BreakpointEditAction::InvertState,
 8297                                        cx,
 8298                                    );
 8299                                })
 8300                                .log_err();
 8301                        }
 8302                    })
 8303                })
 8304                .entry(set_breakpoint_msg, None, {
 8305                    let weak_editor = weak_editor.clone();
 8306                    let breakpoint = breakpoint.clone();
 8307                    move |_window, cx| {
 8308                        weak_editor
 8309                            .update(cx, |this, cx| {
 8310                                this.edit_breakpoint_at_anchor(
 8311                                    anchor,
 8312                                    breakpoint.as_ref().clone(),
 8313                                    BreakpointEditAction::Toggle,
 8314                                    cx,
 8315                                );
 8316                            })
 8317                            .log_err();
 8318                    }
 8319                })
 8320                .entry(log_breakpoint_msg, None, {
 8321                    let breakpoint = breakpoint.clone();
 8322                    let weak_editor = weak_editor.clone();
 8323                    move |window, cx| {
 8324                        weak_editor
 8325                            .update(cx, |this, cx| {
 8326                                this.add_edit_breakpoint_block(
 8327                                    anchor,
 8328                                    breakpoint.as_ref(),
 8329                                    BreakpointPromptEditAction::Log,
 8330                                    window,
 8331                                    cx,
 8332                                );
 8333                            })
 8334                            .log_err();
 8335                    }
 8336                })
 8337                .entry(condition_breakpoint_msg, None, {
 8338                    let breakpoint = breakpoint.clone();
 8339                    let weak_editor = weak_editor.clone();
 8340                    move |window, cx| {
 8341                        weak_editor
 8342                            .update(cx, |this, cx| {
 8343                                this.add_edit_breakpoint_block(
 8344                                    anchor,
 8345                                    breakpoint.as_ref(),
 8346                                    BreakpointPromptEditAction::Condition,
 8347                                    window,
 8348                                    cx,
 8349                                );
 8350                            })
 8351                            .log_err();
 8352                    }
 8353                })
 8354                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8355                    weak_editor
 8356                        .update(cx, |this, cx| {
 8357                            this.add_edit_breakpoint_block(
 8358                                anchor,
 8359                                breakpoint.as_ref(),
 8360                                BreakpointPromptEditAction::HitCondition,
 8361                                window,
 8362                                cx,
 8363                            );
 8364                        })
 8365                        .log_err();
 8366                })
 8367        })
 8368    }
 8369
 8370    fn render_breakpoint(
 8371        &self,
 8372        position: Anchor,
 8373        row: DisplayRow,
 8374        breakpoint: &Breakpoint,
 8375        state: Option<BreakpointSessionState>,
 8376        cx: &mut Context<Self>,
 8377    ) -> IconButton {
 8378        let is_rejected = state.is_some_and(|s| !s.verified);
 8379        // Is it a breakpoint that shows up when hovering over gutter?
 8380        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8381            (false, false),
 8382            |PhantomBreakpointIndicator {
 8383                 is_active,
 8384                 display_row,
 8385                 collides_with_existing_breakpoint,
 8386             }| {
 8387                (
 8388                    is_active && display_row == row,
 8389                    collides_with_existing_breakpoint,
 8390                )
 8391            },
 8392        );
 8393
 8394        let (color, icon) = {
 8395            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8396                (false, false) => ui::IconName::DebugBreakpoint,
 8397                (true, false) => ui::IconName::DebugLogBreakpoint,
 8398                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8399                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8400            };
 8401
 8402            let color = if is_phantom {
 8403                Color::Hint
 8404            } else if is_rejected {
 8405                Color::Disabled
 8406            } else {
 8407                Color::Debugger
 8408            };
 8409
 8410            (color, icon)
 8411        };
 8412
 8413        let breakpoint = Arc::from(breakpoint.clone());
 8414
 8415        let alt_as_text = gpui::Keystroke {
 8416            modifiers: Modifiers::secondary_key(),
 8417            ..Default::default()
 8418        };
 8419        let primary_action_text = if breakpoint.is_disabled() {
 8420            "Enable breakpoint"
 8421        } else if is_phantom && !collides_with_existing {
 8422            "Set breakpoint"
 8423        } else {
 8424            "Unset breakpoint"
 8425        };
 8426        let focus_handle = self.focus_handle.clone();
 8427
 8428        let meta = if is_rejected {
 8429            SharedString::from("No executable code is associated with this line.")
 8430        } else if collides_with_existing && !breakpoint.is_disabled() {
 8431            SharedString::from(format!(
 8432                "{alt_as_text}-click to disable,\nright-click for more options."
 8433            ))
 8434        } else {
 8435            SharedString::from("Right-click for more options.")
 8436        };
 8437        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8438            .icon_size(IconSize::XSmall)
 8439            .size(ui::ButtonSize::None)
 8440            .when(is_rejected, |this| {
 8441                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8442            })
 8443            .icon_color(color)
 8444            .style(ButtonStyle::Transparent)
 8445            .on_click(cx.listener({
 8446                move |editor, event: &ClickEvent, window, cx| {
 8447                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8448                        BreakpointEditAction::InvertState
 8449                    } else {
 8450                        BreakpointEditAction::Toggle
 8451                    };
 8452
 8453                    window.focus(&editor.focus_handle(cx));
 8454                    editor.edit_breakpoint_at_anchor(
 8455                        position,
 8456                        breakpoint.as_ref().clone(),
 8457                        edit_action,
 8458                        cx,
 8459                    );
 8460                }
 8461            }))
 8462            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8463                editor.set_breakpoint_context_menu(
 8464                    row,
 8465                    Some(position),
 8466                    event.position(),
 8467                    window,
 8468                    cx,
 8469                );
 8470            }))
 8471            .tooltip(move |window, cx| {
 8472                Tooltip::with_meta_in(
 8473                    primary_action_text,
 8474                    Some(&ToggleBreakpoint),
 8475                    meta.clone(),
 8476                    &focus_handle,
 8477                    window,
 8478                    cx,
 8479                )
 8480            })
 8481    }
 8482
 8483    fn build_tasks_context(
 8484        project: &Entity<Project>,
 8485        buffer: &Entity<Buffer>,
 8486        buffer_row: u32,
 8487        tasks: &Arc<RunnableTasks>,
 8488        cx: &mut Context<Self>,
 8489    ) -> Task<Option<task::TaskContext>> {
 8490        let position = Point::new(buffer_row, tasks.column);
 8491        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8492        let location = Location {
 8493            buffer: buffer.clone(),
 8494            range: range_start..range_start,
 8495        };
 8496        // Fill in the environmental variables from the tree-sitter captures
 8497        let mut captured_task_variables = TaskVariables::default();
 8498        for (capture_name, value) in tasks.extra_variables.clone() {
 8499            captured_task_variables.insert(
 8500                task::VariableName::Custom(capture_name.into()),
 8501                value.clone(),
 8502            );
 8503        }
 8504        project.update(cx, |project, cx| {
 8505            project.task_store().update(cx, |task_store, cx| {
 8506                task_store.task_context_for_location(captured_task_variables, location, cx)
 8507            })
 8508        })
 8509    }
 8510
 8511    pub fn spawn_nearest_task(
 8512        &mut self,
 8513        action: &SpawnNearestTask,
 8514        window: &mut Window,
 8515        cx: &mut Context<Self>,
 8516    ) {
 8517        let Some((workspace, _)) = self.workspace.clone() else {
 8518            return;
 8519        };
 8520        let Some(project) = self.project.clone() else {
 8521            return;
 8522        };
 8523
 8524        // Try to find a closest, enclosing node using tree-sitter that has a task
 8525        let Some((buffer, buffer_row, tasks)) = self
 8526            .find_enclosing_node_task(cx)
 8527            // Or find the task that's closest in row-distance.
 8528            .or_else(|| self.find_closest_task(cx))
 8529        else {
 8530            return;
 8531        };
 8532
 8533        let reveal_strategy = action.reveal;
 8534        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8535        cx.spawn_in(window, async move |_, cx| {
 8536            let context = task_context.await?;
 8537            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8538
 8539            let resolved = &mut resolved_task.resolved;
 8540            resolved.reveal = reveal_strategy;
 8541
 8542            workspace
 8543                .update_in(cx, |workspace, window, cx| {
 8544                    workspace.schedule_resolved_task(
 8545                        task_source_kind,
 8546                        resolved_task,
 8547                        false,
 8548                        window,
 8549                        cx,
 8550                    );
 8551                })
 8552                .ok()
 8553        })
 8554        .detach();
 8555    }
 8556
 8557    fn find_closest_task(
 8558        &mut self,
 8559        cx: &mut Context<Self>,
 8560    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8561        let cursor_row = self
 8562            .selections
 8563            .newest_adjusted(&self.display_snapshot(cx))
 8564            .head()
 8565            .row;
 8566
 8567        let ((buffer_id, row), tasks) = self
 8568            .tasks
 8569            .iter()
 8570            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8571
 8572        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8573        let tasks = Arc::new(tasks.to_owned());
 8574        Some((buffer, *row, tasks))
 8575    }
 8576
 8577    fn find_enclosing_node_task(
 8578        &mut self,
 8579        cx: &mut Context<Self>,
 8580    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8581        let snapshot = self.buffer.read(cx).snapshot(cx);
 8582        let offset = self
 8583            .selections
 8584            .newest::<usize>(&self.display_snapshot(cx))
 8585            .head();
 8586        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8587        let buffer_id = excerpt.buffer().remote_id();
 8588
 8589        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8590        let mut cursor = layer.node().walk();
 8591
 8592        while cursor.goto_first_child_for_byte(offset).is_some() {
 8593            if cursor.node().end_byte() == offset {
 8594                cursor.goto_next_sibling();
 8595            }
 8596        }
 8597
 8598        // Ascend to the smallest ancestor that contains the range and has a task.
 8599        loop {
 8600            let node = cursor.node();
 8601            let node_range = node.byte_range();
 8602            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8603
 8604            // Check if this node contains our offset
 8605            if node_range.start <= offset && node_range.end >= offset {
 8606                // If it contains offset, check for task
 8607                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8608                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8609                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8610                }
 8611            }
 8612
 8613            if !cursor.goto_parent() {
 8614                break;
 8615            }
 8616        }
 8617        None
 8618    }
 8619
 8620    fn render_run_indicator(
 8621        &self,
 8622        _style: &EditorStyle,
 8623        is_active: bool,
 8624        row: DisplayRow,
 8625        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8626        cx: &mut Context<Self>,
 8627    ) -> IconButton {
 8628        let color = Color::Muted;
 8629        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8630
 8631        IconButton::new(
 8632            ("run_indicator", row.0 as usize),
 8633            ui::IconName::PlayOutlined,
 8634        )
 8635        .shape(ui::IconButtonShape::Square)
 8636        .icon_size(IconSize::XSmall)
 8637        .icon_color(color)
 8638        .toggle_state(is_active)
 8639        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8640            let quick_launch = match e {
 8641                ClickEvent::Keyboard(_) => true,
 8642                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8643            };
 8644
 8645            window.focus(&editor.focus_handle(cx));
 8646            editor.toggle_code_actions(
 8647                &ToggleCodeActions {
 8648                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8649                    quick_launch,
 8650                },
 8651                window,
 8652                cx,
 8653            );
 8654        }))
 8655        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8656            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8657        }))
 8658    }
 8659
 8660    pub fn context_menu_visible(&self) -> bool {
 8661        !self.edit_prediction_preview_is_active()
 8662            && self
 8663                .context_menu
 8664                .borrow()
 8665                .as_ref()
 8666                .is_some_and(|menu| menu.visible())
 8667    }
 8668
 8669    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8670        self.context_menu
 8671            .borrow()
 8672            .as_ref()
 8673            .map(|menu| menu.origin())
 8674    }
 8675
 8676    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8677        self.context_menu_options = Some(options);
 8678    }
 8679
 8680    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8681    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8682
 8683    fn render_edit_prediction_popover(
 8684        &mut self,
 8685        text_bounds: &Bounds<Pixels>,
 8686        content_origin: gpui::Point<Pixels>,
 8687        right_margin: Pixels,
 8688        editor_snapshot: &EditorSnapshot,
 8689        visible_row_range: Range<DisplayRow>,
 8690        scroll_top: ScrollOffset,
 8691        scroll_bottom: ScrollOffset,
 8692        line_layouts: &[LineWithInvisibles],
 8693        line_height: Pixels,
 8694        scroll_position: gpui::Point<ScrollOffset>,
 8695        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8696        newest_selection_head: Option<DisplayPoint>,
 8697        editor_width: Pixels,
 8698        style: &EditorStyle,
 8699        window: &mut Window,
 8700        cx: &mut App,
 8701    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8702        if self.mode().is_minimap() {
 8703            return None;
 8704        }
 8705        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8706
 8707        if self.edit_prediction_visible_in_cursor_popover(true) {
 8708            return None;
 8709        }
 8710
 8711        match &active_edit_prediction.completion {
 8712            EditPrediction::MoveWithin { target, .. } => {
 8713                let target_display_point = target.to_display_point(editor_snapshot);
 8714
 8715                if self.edit_prediction_requires_modifier() {
 8716                    if !self.edit_prediction_preview_is_active() {
 8717                        return None;
 8718                    }
 8719
 8720                    self.render_edit_prediction_modifier_jump_popover(
 8721                        text_bounds,
 8722                        content_origin,
 8723                        visible_row_range,
 8724                        line_layouts,
 8725                        line_height,
 8726                        scroll_pixel_position,
 8727                        newest_selection_head,
 8728                        target_display_point,
 8729                        window,
 8730                        cx,
 8731                    )
 8732                } else {
 8733                    self.render_edit_prediction_eager_jump_popover(
 8734                        text_bounds,
 8735                        content_origin,
 8736                        editor_snapshot,
 8737                        visible_row_range,
 8738                        scroll_top,
 8739                        scroll_bottom,
 8740                        line_height,
 8741                        scroll_pixel_position,
 8742                        target_display_point,
 8743                        editor_width,
 8744                        window,
 8745                        cx,
 8746                    )
 8747                }
 8748            }
 8749            EditPrediction::Edit {
 8750                display_mode: EditDisplayMode::Inline,
 8751                ..
 8752            } => None,
 8753            EditPrediction::Edit {
 8754                display_mode: EditDisplayMode::TabAccept,
 8755                edits,
 8756                ..
 8757            } => {
 8758                let range = &edits.first()?.0;
 8759                let target_display_point = range.end.to_display_point(editor_snapshot);
 8760
 8761                self.render_edit_prediction_end_of_line_popover(
 8762                    "Accept",
 8763                    editor_snapshot,
 8764                    visible_row_range,
 8765                    target_display_point,
 8766                    line_height,
 8767                    scroll_pixel_position,
 8768                    content_origin,
 8769                    editor_width,
 8770                    window,
 8771                    cx,
 8772                )
 8773            }
 8774            EditPrediction::Edit {
 8775                edits,
 8776                edit_preview,
 8777                display_mode: EditDisplayMode::DiffPopover,
 8778                snapshot,
 8779            } => self.render_edit_prediction_diff_popover(
 8780                text_bounds,
 8781                content_origin,
 8782                right_margin,
 8783                editor_snapshot,
 8784                visible_row_range,
 8785                line_layouts,
 8786                line_height,
 8787                scroll_position,
 8788                scroll_pixel_position,
 8789                newest_selection_head,
 8790                editor_width,
 8791                style,
 8792                edits,
 8793                edit_preview,
 8794                snapshot,
 8795                window,
 8796                cx,
 8797            ),
 8798            EditPrediction::MoveOutside { snapshot, .. } => {
 8799                let file_name = snapshot
 8800                    .file()
 8801                    .map(|file| file.file_name(cx))
 8802                    .unwrap_or("untitled");
 8803                let mut element = self
 8804                    .render_edit_prediction_line_popover(
 8805                        format!("Jump to {file_name}"),
 8806                        Some(IconName::ZedPredict),
 8807                        window,
 8808                        cx,
 8809                    )
 8810                    .into_any();
 8811
 8812                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8813                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8814                let origin_y = text_bounds.size.height - size.height - px(30.);
 8815                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8816                element.prepaint_at(origin, window, cx);
 8817
 8818                Some((element, origin))
 8819            }
 8820        }
 8821    }
 8822
 8823    fn render_edit_prediction_modifier_jump_popover(
 8824        &mut self,
 8825        text_bounds: &Bounds<Pixels>,
 8826        content_origin: gpui::Point<Pixels>,
 8827        visible_row_range: Range<DisplayRow>,
 8828        line_layouts: &[LineWithInvisibles],
 8829        line_height: Pixels,
 8830        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8831        newest_selection_head: Option<DisplayPoint>,
 8832        target_display_point: DisplayPoint,
 8833        window: &mut Window,
 8834        cx: &mut App,
 8835    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8836        let scrolled_content_origin =
 8837            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8838
 8839        const SCROLL_PADDING_Y: Pixels = px(12.);
 8840
 8841        if target_display_point.row() < visible_row_range.start {
 8842            return self.render_edit_prediction_scroll_popover(
 8843                |_| SCROLL_PADDING_Y,
 8844                IconName::ArrowUp,
 8845                visible_row_range,
 8846                line_layouts,
 8847                newest_selection_head,
 8848                scrolled_content_origin,
 8849                window,
 8850                cx,
 8851            );
 8852        } else if target_display_point.row() >= visible_row_range.end {
 8853            return self.render_edit_prediction_scroll_popover(
 8854                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8855                IconName::ArrowDown,
 8856                visible_row_range,
 8857                line_layouts,
 8858                newest_selection_head,
 8859                scrolled_content_origin,
 8860                window,
 8861                cx,
 8862            );
 8863        }
 8864
 8865        const POLE_WIDTH: Pixels = px(2.);
 8866
 8867        let line_layout =
 8868            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8869        let target_column = target_display_point.column() as usize;
 8870
 8871        let target_x = line_layout.x_for_index(target_column);
 8872        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8873            - scroll_pixel_position.y;
 8874
 8875        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8876
 8877        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8878        border_color.l += 0.001;
 8879
 8880        let mut element = v_flex()
 8881            .items_end()
 8882            .when(flag_on_right, |el| el.items_start())
 8883            .child(if flag_on_right {
 8884                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8885                    .rounded_bl(px(0.))
 8886                    .rounded_tl(px(0.))
 8887                    .border_l_2()
 8888                    .border_color(border_color)
 8889            } else {
 8890                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8891                    .rounded_br(px(0.))
 8892                    .rounded_tr(px(0.))
 8893                    .border_r_2()
 8894                    .border_color(border_color)
 8895            })
 8896            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8897            .into_any();
 8898
 8899        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8900
 8901        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8902            - point(
 8903                if flag_on_right {
 8904                    POLE_WIDTH
 8905                } else {
 8906                    size.width - POLE_WIDTH
 8907                },
 8908                size.height - line_height,
 8909            );
 8910
 8911        origin.x = origin.x.max(content_origin.x);
 8912
 8913        element.prepaint_at(origin, window, cx);
 8914
 8915        Some((element, origin))
 8916    }
 8917
 8918    fn render_edit_prediction_scroll_popover(
 8919        &mut self,
 8920        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8921        scroll_icon: IconName,
 8922        visible_row_range: Range<DisplayRow>,
 8923        line_layouts: &[LineWithInvisibles],
 8924        newest_selection_head: Option<DisplayPoint>,
 8925        scrolled_content_origin: gpui::Point<Pixels>,
 8926        window: &mut Window,
 8927        cx: &mut App,
 8928    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8929        let mut element = self
 8930            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8931            .into_any();
 8932
 8933        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8934
 8935        let cursor = newest_selection_head?;
 8936        let cursor_row_layout =
 8937            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8938        let cursor_column = cursor.column() as usize;
 8939
 8940        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8941
 8942        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8943
 8944        element.prepaint_at(origin, window, cx);
 8945        Some((element, origin))
 8946    }
 8947
 8948    fn render_edit_prediction_eager_jump_popover(
 8949        &mut self,
 8950        text_bounds: &Bounds<Pixels>,
 8951        content_origin: gpui::Point<Pixels>,
 8952        editor_snapshot: &EditorSnapshot,
 8953        visible_row_range: Range<DisplayRow>,
 8954        scroll_top: ScrollOffset,
 8955        scroll_bottom: ScrollOffset,
 8956        line_height: Pixels,
 8957        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8958        target_display_point: DisplayPoint,
 8959        editor_width: Pixels,
 8960        window: &mut Window,
 8961        cx: &mut App,
 8962    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8963        if target_display_point.row().as_f64() < scroll_top {
 8964            let mut element = self
 8965                .render_edit_prediction_line_popover(
 8966                    "Jump to Edit",
 8967                    Some(IconName::ArrowUp),
 8968                    window,
 8969                    cx,
 8970                )
 8971                .into_any();
 8972
 8973            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8974            let offset = point(
 8975                (text_bounds.size.width - size.width) / 2.,
 8976                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8977            );
 8978
 8979            let origin = text_bounds.origin + offset;
 8980            element.prepaint_at(origin, window, cx);
 8981            Some((element, origin))
 8982        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8983            let mut element = self
 8984                .render_edit_prediction_line_popover(
 8985                    "Jump to Edit",
 8986                    Some(IconName::ArrowDown),
 8987                    window,
 8988                    cx,
 8989                )
 8990                .into_any();
 8991
 8992            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8993            let offset = point(
 8994                (text_bounds.size.width - size.width) / 2.,
 8995                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8996            );
 8997
 8998            let origin = text_bounds.origin + offset;
 8999            element.prepaint_at(origin, window, cx);
 9000            Some((element, origin))
 9001        } else {
 9002            self.render_edit_prediction_end_of_line_popover(
 9003                "Jump to Edit",
 9004                editor_snapshot,
 9005                visible_row_range,
 9006                target_display_point,
 9007                line_height,
 9008                scroll_pixel_position,
 9009                content_origin,
 9010                editor_width,
 9011                window,
 9012                cx,
 9013            )
 9014        }
 9015    }
 9016
 9017    fn render_edit_prediction_end_of_line_popover(
 9018        self: &mut Editor,
 9019        label: &'static str,
 9020        editor_snapshot: &EditorSnapshot,
 9021        visible_row_range: Range<DisplayRow>,
 9022        target_display_point: DisplayPoint,
 9023        line_height: Pixels,
 9024        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9025        content_origin: gpui::Point<Pixels>,
 9026        editor_width: Pixels,
 9027        window: &mut Window,
 9028        cx: &mut App,
 9029    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9030        let target_line_end = DisplayPoint::new(
 9031            target_display_point.row(),
 9032            editor_snapshot.line_len(target_display_point.row()),
 9033        );
 9034
 9035        let mut element = self
 9036            .render_edit_prediction_line_popover(label, None, window, cx)
 9037            .into_any();
 9038
 9039        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9040
 9041        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9042
 9043        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9044        let mut origin = start_point
 9045            + line_origin
 9046            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9047        origin.x = origin.x.max(content_origin.x);
 9048
 9049        let max_x = content_origin.x + editor_width - size.width;
 9050
 9051        if origin.x > max_x {
 9052            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9053
 9054            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9055                origin.y += offset;
 9056                IconName::ArrowUp
 9057            } else {
 9058                origin.y -= offset;
 9059                IconName::ArrowDown
 9060            };
 9061
 9062            element = self
 9063                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9064                .into_any();
 9065
 9066            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9067
 9068            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9069        }
 9070
 9071        element.prepaint_at(origin, window, cx);
 9072        Some((element, origin))
 9073    }
 9074
 9075    fn render_edit_prediction_diff_popover(
 9076        self: &Editor,
 9077        text_bounds: &Bounds<Pixels>,
 9078        content_origin: gpui::Point<Pixels>,
 9079        right_margin: Pixels,
 9080        editor_snapshot: &EditorSnapshot,
 9081        visible_row_range: Range<DisplayRow>,
 9082        line_layouts: &[LineWithInvisibles],
 9083        line_height: Pixels,
 9084        scroll_position: gpui::Point<ScrollOffset>,
 9085        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9086        newest_selection_head: Option<DisplayPoint>,
 9087        editor_width: Pixels,
 9088        style: &EditorStyle,
 9089        edits: &Vec<(Range<Anchor>, String)>,
 9090        edit_preview: &Option<language::EditPreview>,
 9091        snapshot: &language::BufferSnapshot,
 9092        window: &mut Window,
 9093        cx: &mut App,
 9094    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9095        let edit_start = edits
 9096            .first()
 9097            .unwrap()
 9098            .0
 9099            .start
 9100            .to_display_point(editor_snapshot);
 9101        let edit_end = edits
 9102            .last()
 9103            .unwrap()
 9104            .0
 9105            .end
 9106            .to_display_point(editor_snapshot);
 9107
 9108        let is_visible = visible_row_range.contains(&edit_start.row())
 9109            || visible_row_range.contains(&edit_end.row());
 9110        if !is_visible {
 9111            return None;
 9112        }
 9113
 9114        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9115            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9116        } else {
 9117            // Fallback for providers without edit_preview
 9118            crate::edit_prediction_fallback_text(edits, cx)
 9119        };
 9120
 9121        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9122        let line_count = highlighted_edits.text.lines().count();
 9123
 9124        const BORDER_WIDTH: Pixels = px(1.);
 9125
 9126        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9127        let has_keybind = keybind.is_some();
 9128
 9129        let mut element = h_flex()
 9130            .items_start()
 9131            .child(
 9132                h_flex()
 9133                    .bg(cx.theme().colors().editor_background)
 9134                    .border(BORDER_WIDTH)
 9135                    .shadow_xs()
 9136                    .border_color(cx.theme().colors().border)
 9137                    .rounded_l_lg()
 9138                    .when(line_count > 1, |el| el.rounded_br_lg())
 9139                    .pr_1()
 9140                    .child(styled_text),
 9141            )
 9142            .child(
 9143                h_flex()
 9144                    .h(line_height + BORDER_WIDTH * 2.)
 9145                    .px_1p5()
 9146                    .gap_1()
 9147                    // Workaround: For some reason, there's a gap if we don't do this
 9148                    .ml(-BORDER_WIDTH)
 9149                    .shadow(vec![gpui::BoxShadow {
 9150                        color: gpui::black().opacity(0.05),
 9151                        offset: point(px(1.), px(1.)),
 9152                        blur_radius: px(2.),
 9153                        spread_radius: px(0.),
 9154                    }])
 9155                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9156                    .border(BORDER_WIDTH)
 9157                    .border_color(cx.theme().colors().border)
 9158                    .rounded_r_lg()
 9159                    .id("edit_prediction_diff_popover_keybind")
 9160                    .when(!has_keybind, |el| {
 9161                        let status_colors = cx.theme().status();
 9162
 9163                        el.bg(status_colors.error_background)
 9164                            .border_color(status_colors.error.opacity(0.6))
 9165                            .child(Icon::new(IconName::Info).color(Color::Error))
 9166                            .cursor_default()
 9167                            .hoverable_tooltip(move |_window, cx| {
 9168                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9169                            })
 9170                    })
 9171                    .children(keybind),
 9172            )
 9173            .into_any();
 9174
 9175        let longest_row =
 9176            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9177        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9178            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9179        } else {
 9180            layout_line(
 9181                longest_row,
 9182                editor_snapshot,
 9183                style,
 9184                editor_width,
 9185                |_| false,
 9186                window,
 9187                cx,
 9188            )
 9189            .width
 9190        };
 9191
 9192        let viewport_bounds =
 9193            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9194                right: -right_margin,
 9195                ..Default::default()
 9196            });
 9197
 9198        let x_after_longest = Pixels::from(
 9199            ScrollPixelOffset::from(
 9200                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9201            ) - scroll_pixel_position.x,
 9202        );
 9203
 9204        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9205
 9206        // Fully visible if it can be displayed within the window (allow overlapping other
 9207        // panes). However, this is only allowed if the popover starts within text_bounds.
 9208        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9209            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9210
 9211        let mut origin = if can_position_to_the_right {
 9212            point(
 9213                x_after_longest,
 9214                text_bounds.origin.y
 9215                    + Pixels::from(
 9216                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9217                            - scroll_pixel_position.y,
 9218                    ),
 9219            )
 9220        } else {
 9221            let cursor_row = newest_selection_head.map(|head| head.row());
 9222            let above_edit = edit_start
 9223                .row()
 9224                .0
 9225                .checked_sub(line_count as u32)
 9226                .map(DisplayRow);
 9227            let below_edit = Some(edit_end.row() + 1);
 9228            let above_cursor =
 9229                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9230            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9231
 9232            // Place the edit popover adjacent to the edit if there is a location
 9233            // available that is onscreen and does not obscure the cursor. Otherwise,
 9234            // place it adjacent to the cursor.
 9235            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9236                .into_iter()
 9237                .flatten()
 9238                .find(|&start_row| {
 9239                    let end_row = start_row + line_count as u32;
 9240                    visible_row_range.contains(&start_row)
 9241                        && visible_row_range.contains(&end_row)
 9242                        && cursor_row
 9243                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9244                })?;
 9245
 9246            content_origin
 9247                + point(
 9248                    Pixels::from(-scroll_pixel_position.x),
 9249                    Pixels::from(
 9250                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9251                    ),
 9252                )
 9253        };
 9254
 9255        origin.x -= BORDER_WIDTH;
 9256
 9257        window.defer_draw(element, origin, 1);
 9258
 9259        // Do not return an element, since it will already be drawn due to defer_draw.
 9260        None
 9261    }
 9262
 9263    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9264        px(30.)
 9265    }
 9266
 9267    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9268        if self.read_only(cx) {
 9269            cx.theme().players().read_only()
 9270        } else {
 9271            self.style.as_ref().unwrap().local_player
 9272        }
 9273    }
 9274
 9275    fn render_edit_prediction_accept_keybind(
 9276        &self,
 9277        window: &mut Window,
 9278        cx: &App,
 9279    ) -> Option<AnyElement> {
 9280        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9281        let accept_keystroke = accept_binding.keystroke()?;
 9282
 9283        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9284
 9285        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9286            Color::Accent
 9287        } else {
 9288            Color::Muted
 9289        };
 9290
 9291        h_flex()
 9292            .px_0p5()
 9293            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9294            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9295            .text_size(TextSize::XSmall.rems(cx))
 9296            .child(h_flex().children(ui::render_modifiers(
 9297                accept_keystroke.modifiers(),
 9298                PlatformStyle::platform(),
 9299                Some(modifiers_color),
 9300                Some(IconSize::XSmall.rems().into()),
 9301                true,
 9302            )))
 9303            .when(is_platform_style_mac, |parent| {
 9304                parent.child(accept_keystroke.key().to_string())
 9305            })
 9306            .when(!is_platform_style_mac, |parent| {
 9307                parent.child(
 9308                    Key::new(
 9309                        util::capitalize(accept_keystroke.key()),
 9310                        Some(Color::Default),
 9311                    )
 9312                    .size(Some(IconSize::XSmall.rems().into())),
 9313                )
 9314            })
 9315            .into_any()
 9316            .into()
 9317    }
 9318
 9319    fn render_edit_prediction_line_popover(
 9320        &self,
 9321        label: impl Into<SharedString>,
 9322        icon: Option<IconName>,
 9323        window: &mut Window,
 9324        cx: &App,
 9325    ) -> Stateful<Div> {
 9326        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9327
 9328        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9329        let has_keybind = keybind.is_some();
 9330
 9331        h_flex()
 9332            .id("ep-line-popover")
 9333            .py_0p5()
 9334            .pl_1()
 9335            .pr(padding_right)
 9336            .gap_1()
 9337            .rounded_md()
 9338            .border_1()
 9339            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9340            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9341            .shadow_xs()
 9342            .when(!has_keybind, |el| {
 9343                let status_colors = cx.theme().status();
 9344
 9345                el.bg(status_colors.error_background)
 9346                    .border_color(status_colors.error.opacity(0.6))
 9347                    .pl_2()
 9348                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9349                    .cursor_default()
 9350                    .hoverable_tooltip(move |_window, cx| {
 9351                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9352                    })
 9353            })
 9354            .children(keybind)
 9355            .child(
 9356                Label::new(label)
 9357                    .size(LabelSize::Small)
 9358                    .when(!has_keybind, |el| {
 9359                        el.color(cx.theme().status().error.into()).strikethrough()
 9360                    }),
 9361            )
 9362            .when(!has_keybind, |el| {
 9363                el.child(
 9364                    h_flex().ml_1().child(
 9365                        Icon::new(IconName::Info)
 9366                            .size(IconSize::Small)
 9367                            .color(cx.theme().status().error.into()),
 9368                    ),
 9369                )
 9370            })
 9371            .when_some(icon, |element, icon| {
 9372                element.child(
 9373                    div()
 9374                        .mt(px(1.5))
 9375                        .child(Icon::new(icon).size(IconSize::Small)),
 9376                )
 9377            })
 9378    }
 9379
 9380    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9381        let accent_color = cx.theme().colors().text_accent;
 9382        let editor_bg_color = cx.theme().colors().editor_background;
 9383        editor_bg_color.blend(accent_color.opacity(0.1))
 9384    }
 9385
 9386    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9387        let accent_color = cx.theme().colors().text_accent;
 9388        let editor_bg_color = cx.theme().colors().editor_background;
 9389        editor_bg_color.blend(accent_color.opacity(0.6))
 9390    }
 9391    fn get_prediction_provider_icon_name(
 9392        provider: &Option<RegisteredEditPredictionProvider>,
 9393    ) -> IconName {
 9394        match provider {
 9395            Some(provider) => match provider.provider.name() {
 9396                "copilot" => IconName::Copilot,
 9397                "supermaven" => IconName::Supermaven,
 9398                _ => IconName::ZedPredict,
 9399            },
 9400            None => IconName::ZedPredict,
 9401        }
 9402    }
 9403
 9404    fn render_edit_prediction_cursor_popover(
 9405        &self,
 9406        min_width: Pixels,
 9407        max_width: Pixels,
 9408        cursor_point: Point,
 9409        style: &EditorStyle,
 9410        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9411        _window: &Window,
 9412        cx: &mut Context<Editor>,
 9413    ) -> Option<AnyElement> {
 9414        let provider = self.edit_prediction_provider.as_ref()?;
 9415        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9416
 9417        let is_refreshing = provider.provider.is_refreshing(cx);
 9418
 9419        fn pending_completion_container(icon: IconName) -> Div {
 9420            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9421        }
 9422
 9423        let completion = match &self.active_edit_prediction {
 9424            Some(prediction) => {
 9425                if !self.has_visible_completions_menu() {
 9426                    const RADIUS: Pixels = px(6.);
 9427                    const BORDER_WIDTH: Pixels = px(1.);
 9428
 9429                    return Some(
 9430                        h_flex()
 9431                            .elevation_2(cx)
 9432                            .border(BORDER_WIDTH)
 9433                            .border_color(cx.theme().colors().border)
 9434                            .when(accept_keystroke.is_none(), |el| {
 9435                                el.border_color(cx.theme().status().error)
 9436                            })
 9437                            .rounded(RADIUS)
 9438                            .rounded_tl(px(0.))
 9439                            .overflow_hidden()
 9440                            .child(div().px_1p5().child(match &prediction.completion {
 9441                                EditPrediction::MoveWithin { target, snapshot } => {
 9442                                    use text::ToPoint as _;
 9443                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9444                                    {
 9445                                        Icon::new(IconName::ZedPredictDown)
 9446                                    } else {
 9447                                        Icon::new(IconName::ZedPredictUp)
 9448                                    }
 9449                                }
 9450                                EditPrediction::MoveOutside { .. } => {
 9451                                    // TODO [zeta2] custom icon for external jump?
 9452                                    Icon::new(provider_icon)
 9453                                }
 9454                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9455                            }))
 9456                            .child(
 9457                                h_flex()
 9458                                    .gap_1()
 9459                                    .py_1()
 9460                                    .px_2()
 9461                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9462                                    .border_l_1()
 9463                                    .border_color(cx.theme().colors().border)
 9464                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9465                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9466                                        el.child(
 9467                                            Label::new("Hold")
 9468                                                .size(LabelSize::Small)
 9469                                                .when(accept_keystroke.is_none(), |el| {
 9470                                                    el.strikethrough()
 9471                                                })
 9472                                                .line_height_style(LineHeightStyle::UiLabel),
 9473                                        )
 9474                                    })
 9475                                    .id("edit_prediction_cursor_popover_keybind")
 9476                                    .when(accept_keystroke.is_none(), |el| {
 9477                                        let status_colors = cx.theme().status();
 9478
 9479                                        el.bg(status_colors.error_background)
 9480                                            .border_color(status_colors.error.opacity(0.6))
 9481                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9482                                            .cursor_default()
 9483                                            .hoverable_tooltip(move |_window, cx| {
 9484                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9485                                                    .into()
 9486                                            })
 9487                                    })
 9488                                    .when_some(
 9489                                        accept_keystroke.as_ref(),
 9490                                        |el, accept_keystroke| {
 9491                                            el.child(h_flex().children(ui::render_modifiers(
 9492                                                accept_keystroke.modifiers(),
 9493                                                PlatformStyle::platform(),
 9494                                                Some(Color::Default),
 9495                                                Some(IconSize::XSmall.rems().into()),
 9496                                                false,
 9497                                            )))
 9498                                        },
 9499                                    ),
 9500                            )
 9501                            .into_any(),
 9502                    );
 9503                }
 9504
 9505                self.render_edit_prediction_cursor_popover_preview(
 9506                    prediction,
 9507                    cursor_point,
 9508                    style,
 9509                    cx,
 9510                )?
 9511            }
 9512
 9513            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9514                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9515                    stale_completion,
 9516                    cursor_point,
 9517                    style,
 9518                    cx,
 9519                )?,
 9520
 9521                None => pending_completion_container(provider_icon)
 9522                    .child(Label::new("...").size(LabelSize::Small)),
 9523            },
 9524
 9525            None => pending_completion_container(provider_icon)
 9526                .child(Label::new("...").size(LabelSize::Small)),
 9527        };
 9528
 9529        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9530            completion
 9531                .with_animation(
 9532                    "loading-completion",
 9533                    Animation::new(Duration::from_secs(2))
 9534                        .repeat()
 9535                        .with_easing(pulsating_between(0.4, 0.8)),
 9536                    |label, delta| label.opacity(delta),
 9537                )
 9538                .into_any_element()
 9539        } else {
 9540            completion.into_any_element()
 9541        };
 9542
 9543        let has_completion = self.active_edit_prediction.is_some();
 9544
 9545        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9546        Some(
 9547            h_flex()
 9548                .min_w(min_width)
 9549                .max_w(max_width)
 9550                .flex_1()
 9551                .elevation_2(cx)
 9552                .border_color(cx.theme().colors().border)
 9553                .child(
 9554                    div()
 9555                        .flex_1()
 9556                        .py_1()
 9557                        .px_2()
 9558                        .overflow_hidden()
 9559                        .child(completion),
 9560                )
 9561                .when_some(accept_keystroke, |el, accept_keystroke| {
 9562                    if !accept_keystroke.modifiers().modified() {
 9563                        return el;
 9564                    }
 9565
 9566                    el.child(
 9567                        h_flex()
 9568                            .h_full()
 9569                            .border_l_1()
 9570                            .rounded_r_lg()
 9571                            .border_color(cx.theme().colors().border)
 9572                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9573                            .gap_1()
 9574                            .py_1()
 9575                            .px_2()
 9576                            .child(
 9577                                h_flex()
 9578                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9579                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9580                                    .child(h_flex().children(ui::render_modifiers(
 9581                                        accept_keystroke.modifiers(),
 9582                                        PlatformStyle::platform(),
 9583                                        Some(if !has_completion {
 9584                                            Color::Muted
 9585                                        } else {
 9586                                            Color::Default
 9587                                        }),
 9588                                        None,
 9589                                        false,
 9590                                    ))),
 9591                            )
 9592                            .child(Label::new("Preview").into_any_element())
 9593                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9594                    )
 9595                })
 9596                .into_any(),
 9597        )
 9598    }
 9599
 9600    fn render_edit_prediction_cursor_popover_preview(
 9601        &self,
 9602        completion: &EditPredictionState,
 9603        cursor_point: Point,
 9604        style: &EditorStyle,
 9605        cx: &mut Context<Editor>,
 9606    ) -> Option<Div> {
 9607        use text::ToPoint as _;
 9608
 9609        fn render_relative_row_jump(
 9610            prefix: impl Into<String>,
 9611            current_row: u32,
 9612            target_row: u32,
 9613        ) -> Div {
 9614            let (row_diff, arrow) = if target_row < current_row {
 9615                (current_row - target_row, IconName::ArrowUp)
 9616            } else {
 9617                (target_row - current_row, IconName::ArrowDown)
 9618            };
 9619
 9620            h_flex()
 9621                .child(
 9622                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9623                        .color(Color::Muted)
 9624                        .size(LabelSize::Small),
 9625                )
 9626                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9627        }
 9628
 9629        let supports_jump = self
 9630            .edit_prediction_provider
 9631            .as_ref()
 9632            .map(|provider| provider.provider.supports_jump_to_edit())
 9633            .unwrap_or(true);
 9634
 9635        match &completion.completion {
 9636            EditPrediction::MoveWithin {
 9637                target, snapshot, ..
 9638            } => {
 9639                if !supports_jump {
 9640                    return None;
 9641                }
 9642
 9643                Some(
 9644                    h_flex()
 9645                        .px_2()
 9646                        .gap_2()
 9647                        .flex_1()
 9648                        .child(
 9649                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9650                                Icon::new(IconName::ZedPredictDown)
 9651                            } else {
 9652                                Icon::new(IconName::ZedPredictUp)
 9653                            },
 9654                        )
 9655                        .child(Label::new("Jump to Edit")),
 9656                )
 9657            }
 9658            EditPrediction::MoveOutside { snapshot, .. } => {
 9659                let file_name = snapshot
 9660                    .file()
 9661                    .map(|file| file.file_name(cx))
 9662                    .unwrap_or("untitled");
 9663                Some(
 9664                    h_flex()
 9665                        .px_2()
 9666                        .gap_2()
 9667                        .flex_1()
 9668                        .child(Icon::new(IconName::ZedPredict))
 9669                        .child(Label::new(format!("Jump to {file_name}"))),
 9670                )
 9671            }
 9672            EditPrediction::Edit {
 9673                edits,
 9674                edit_preview,
 9675                snapshot,
 9676                display_mode: _,
 9677            } => {
 9678                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9679
 9680                let (highlighted_edits, has_more_lines) =
 9681                    if let Some(edit_preview) = edit_preview.as_ref() {
 9682                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9683                            .first_line_preview()
 9684                    } else {
 9685                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9686                    };
 9687
 9688                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9689                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9690
 9691                let preview = h_flex()
 9692                    .gap_1()
 9693                    .min_w_16()
 9694                    .child(styled_text)
 9695                    .when(has_more_lines, |parent| parent.child(""));
 9696
 9697                let left = if supports_jump && first_edit_row != cursor_point.row {
 9698                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9699                        .into_any_element()
 9700                } else {
 9701                    let icon_name =
 9702                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9703                    Icon::new(icon_name).into_any_element()
 9704                };
 9705
 9706                Some(
 9707                    h_flex()
 9708                        .h_full()
 9709                        .flex_1()
 9710                        .gap_2()
 9711                        .pr_1()
 9712                        .overflow_x_hidden()
 9713                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9714                        .child(left)
 9715                        .child(preview),
 9716                )
 9717            }
 9718        }
 9719    }
 9720
 9721    pub fn render_context_menu(
 9722        &self,
 9723        style: &EditorStyle,
 9724        max_height_in_lines: u32,
 9725        window: &mut Window,
 9726        cx: &mut Context<Editor>,
 9727    ) -> Option<AnyElement> {
 9728        let menu = self.context_menu.borrow();
 9729        let menu = menu.as_ref()?;
 9730        if !menu.visible() {
 9731            return None;
 9732        };
 9733        Some(menu.render(style, max_height_in_lines, window, cx))
 9734    }
 9735
 9736    fn render_context_menu_aside(
 9737        &mut self,
 9738        max_size: Size<Pixels>,
 9739        window: &mut Window,
 9740        cx: &mut Context<Editor>,
 9741    ) -> Option<AnyElement> {
 9742        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9743            if menu.visible() {
 9744                menu.render_aside(max_size, window, cx)
 9745            } else {
 9746                None
 9747            }
 9748        })
 9749    }
 9750
 9751    fn hide_context_menu(
 9752        &mut self,
 9753        window: &mut Window,
 9754        cx: &mut Context<Self>,
 9755    ) -> Option<CodeContextMenu> {
 9756        cx.notify();
 9757        self.completion_tasks.clear();
 9758        let context_menu = self.context_menu.borrow_mut().take();
 9759        self.stale_edit_prediction_in_menu.take();
 9760        self.update_visible_edit_prediction(window, cx);
 9761        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9762            && let Some(completion_provider) = &self.completion_provider
 9763        {
 9764            completion_provider.selection_changed(None, window, cx);
 9765        }
 9766        context_menu
 9767    }
 9768
 9769    fn show_snippet_choices(
 9770        &mut self,
 9771        choices: &Vec<String>,
 9772        selection: Range<Anchor>,
 9773        cx: &mut Context<Self>,
 9774    ) {
 9775        let Some((_, buffer, _)) = self
 9776            .buffer()
 9777            .read(cx)
 9778            .excerpt_containing(selection.start, cx)
 9779        else {
 9780            return;
 9781        };
 9782        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9783        else {
 9784            return;
 9785        };
 9786        if buffer != end_buffer {
 9787            log::error!("expected anchor range to have matching buffer IDs");
 9788            return;
 9789        }
 9790
 9791        let id = post_inc(&mut self.next_completion_id);
 9792        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9793        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9794            CompletionsMenu::new_snippet_choices(
 9795                id,
 9796                true,
 9797                choices,
 9798                selection,
 9799                buffer,
 9800                snippet_sort_order,
 9801            ),
 9802        ));
 9803    }
 9804
 9805    pub fn insert_snippet(
 9806        &mut self,
 9807        insertion_ranges: &[Range<usize>],
 9808        snippet: Snippet,
 9809        window: &mut Window,
 9810        cx: &mut Context<Self>,
 9811    ) -> Result<()> {
 9812        struct Tabstop<T> {
 9813            is_end_tabstop: bool,
 9814            ranges: Vec<Range<T>>,
 9815            choices: Option<Vec<String>>,
 9816        }
 9817
 9818        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9819            let snippet_text: Arc<str> = snippet.text.clone().into();
 9820            let edits = insertion_ranges
 9821                .iter()
 9822                .cloned()
 9823                .map(|range| (range, snippet_text.clone()));
 9824            let autoindent_mode = AutoindentMode::Block {
 9825                original_indent_columns: Vec::new(),
 9826            };
 9827            buffer.edit(edits, Some(autoindent_mode), cx);
 9828
 9829            let snapshot = &*buffer.read(cx);
 9830            let snippet = &snippet;
 9831            snippet
 9832                .tabstops
 9833                .iter()
 9834                .map(|tabstop| {
 9835                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9836                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9837                    });
 9838                    let mut tabstop_ranges = tabstop
 9839                        .ranges
 9840                        .iter()
 9841                        .flat_map(|tabstop_range| {
 9842                            let mut delta = 0_isize;
 9843                            insertion_ranges.iter().map(move |insertion_range| {
 9844                                let insertion_start = insertion_range.start as isize + delta;
 9845                                delta +=
 9846                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9847
 9848                                let start = ((insertion_start + tabstop_range.start) as usize)
 9849                                    .min(snapshot.len());
 9850                                let end = ((insertion_start + tabstop_range.end) as usize)
 9851                                    .min(snapshot.len());
 9852                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9853                            })
 9854                        })
 9855                        .collect::<Vec<_>>();
 9856                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9857
 9858                    Tabstop {
 9859                        is_end_tabstop,
 9860                        ranges: tabstop_ranges,
 9861                        choices: tabstop.choices.clone(),
 9862                    }
 9863                })
 9864                .collect::<Vec<_>>()
 9865        });
 9866        if let Some(tabstop) = tabstops.first() {
 9867            self.change_selections(Default::default(), window, cx, |s| {
 9868                // Reverse order so that the first range is the newest created selection.
 9869                // Completions will use it and autoscroll will prioritize it.
 9870                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9871            });
 9872
 9873            if let Some(choices) = &tabstop.choices
 9874                && let Some(selection) = tabstop.ranges.first()
 9875            {
 9876                self.show_snippet_choices(choices, selection.clone(), cx)
 9877            }
 9878
 9879            // If we're already at the last tabstop and it's at the end of the snippet,
 9880            // we're done, we don't need to keep the state around.
 9881            if !tabstop.is_end_tabstop {
 9882                let choices = tabstops
 9883                    .iter()
 9884                    .map(|tabstop| tabstop.choices.clone())
 9885                    .collect();
 9886
 9887                let ranges = tabstops
 9888                    .into_iter()
 9889                    .map(|tabstop| tabstop.ranges)
 9890                    .collect::<Vec<_>>();
 9891
 9892                self.snippet_stack.push(SnippetState {
 9893                    active_index: 0,
 9894                    ranges,
 9895                    choices,
 9896                });
 9897            }
 9898
 9899            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9900            if self.autoclose_regions.is_empty() {
 9901                let snapshot = self.buffer.read(cx).snapshot(cx);
 9902                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9903                    let selection_head = selection.head();
 9904                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9905                        continue;
 9906                    };
 9907
 9908                    let mut bracket_pair = None;
 9909                    let max_lookup_length = scope
 9910                        .brackets()
 9911                        .map(|(pair, _)| {
 9912                            pair.start
 9913                                .as_str()
 9914                                .chars()
 9915                                .count()
 9916                                .max(pair.end.as_str().chars().count())
 9917                        })
 9918                        .max();
 9919                    if let Some(max_lookup_length) = max_lookup_length {
 9920                        let next_text = snapshot
 9921                            .chars_at(selection_head)
 9922                            .take(max_lookup_length)
 9923                            .collect::<String>();
 9924                        let prev_text = snapshot
 9925                            .reversed_chars_at(selection_head)
 9926                            .take(max_lookup_length)
 9927                            .collect::<String>();
 9928
 9929                        for (pair, enabled) in scope.brackets() {
 9930                            if enabled
 9931                                && pair.close
 9932                                && prev_text.starts_with(pair.start.as_str())
 9933                                && next_text.starts_with(pair.end.as_str())
 9934                            {
 9935                                bracket_pair = Some(pair.clone());
 9936                                break;
 9937                            }
 9938                        }
 9939                    }
 9940
 9941                    if let Some(pair) = bracket_pair {
 9942                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9943                        let autoclose_enabled =
 9944                            self.use_autoclose && snapshot_settings.use_autoclose;
 9945                        if autoclose_enabled {
 9946                            let start = snapshot.anchor_after(selection_head);
 9947                            let end = snapshot.anchor_after(selection_head);
 9948                            self.autoclose_regions.push(AutocloseRegion {
 9949                                selection_id: selection.id,
 9950                                range: start..end,
 9951                                pair,
 9952                            });
 9953                        }
 9954                    }
 9955                }
 9956            }
 9957        }
 9958        Ok(())
 9959    }
 9960
 9961    pub fn move_to_next_snippet_tabstop(
 9962        &mut self,
 9963        window: &mut Window,
 9964        cx: &mut Context<Self>,
 9965    ) -> bool {
 9966        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9967    }
 9968
 9969    pub fn move_to_prev_snippet_tabstop(
 9970        &mut self,
 9971        window: &mut Window,
 9972        cx: &mut Context<Self>,
 9973    ) -> bool {
 9974        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9975    }
 9976
 9977    pub fn move_to_snippet_tabstop(
 9978        &mut self,
 9979        bias: Bias,
 9980        window: &mut Window,
 9981        cx: &mut Context<Self>,
 9982    ) -> bool {
 9983        if let Some(mut snippet) = self.snippet_stack.pop() {
 9984            match bias {
 9985                Bias::Left => {
 9986                    if snippet.active_index > 0 {
 9987                        snippet.active_index -= 1;
 9988                    } else {
 9989                        self.snippet_stack.push(snippet);
 9990                        return false;
 9991                    }
 9992                }
 9993                Bias::Right => {
 9994                    if snippet.active_index + 1 < snippet.ranges.len() {
 9995                        snippet.active_index += 1;
 9996                    } else {
 9997                        self.snippet_stack.push(snippet);
 9998                        return false;
 9999                    }
10000                }
10001            }
10002            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10003                self.change_selections(Default::default(), window, cx, |s| {
10004                    // Reverse order so that the first range is the newest created selection.
10005                    // Completions will use it and autoscroll will prioritize it.
10006                    s.select_ranges(current_ranges.iter().rev().cloned())
10007                });
10008
10009                if let Some(choices) = &snippet.choices[snippet.active_index]
10010                    && let Some(selection) = current_ranges.first()
10011                {
10012                    self.show_snippet_choices(choices, selection.clone(), cx);
10013                }
10014
10015                // If snippet state is not at the last tabstop, push it back on the stack
10016                if snippet.active_index + 1 < snippet.ranges.len() {
10017                    self.snippet_stack.push(snippet);
10018                }
10019                return true;
10020            }
10021        }
10022
10023        false
10024    }
10025
10026    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10027        self.transact(window, cx, |this, window, cx| {
10028            this.select_all(&SelectAll, window, cx);
10029            this.insert("", window, cx);
10030        });
10031    }
10032
10033    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10034        if self.read_only(cx) {
10035            return;
10036        }
10037        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10038        self.transact(window, cx, |this, window, cx| {
10039            this.select_autoclose_pair(window, cx);
10040
10041            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10042
10043            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10044            if !this.linked_edit_ranges.is_empty() {
10045                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10046                let snapshot = this.buffer.read(cx).snapshot(cx);
10047
10048                for selection in selections.iter() {
10049                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10050                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10051                    if selection_start.buffer_id != selection_end.buffer_id {
10052                        continue;
10053                    }
10054                    if let Some(ranges) =
10055                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10056                    {
10057                        for (buffer, entries) in ranges {
10058                            linked_ranges.entry(buffer).or_default().extend(entries);
10059                        }
10060                    }
10061                }
10062            }
10063
10064            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10065            for selection in &mut selections {
10066                if selection.is_empty() {
10067                    let old_head = selection.head();
10068                    let mut new_head =
10069                        movement::left(&display_map, old_head.to_display_point(&display_map))
10070                            .to_point(&display_map);
10071                    if let Some((buffer, line_buffer_range)) = display_map
10072                        .buffer_snapshot()
10073                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10074                    {
10075                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10076                        let indent_len = match indent_size.kind {
10077                            IndentKind::Space => {
10078                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10079                            }
10080                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10081                        };
10082                        if old_head.column <= indent_size.len && old_head.column > 0 {
10083                            let indent_len = indent_len.get();
10084                            new_head = cmp::min(
10085                                new_head,
10086                                MultiBufferPoint::new(
10087                                    old_head.row,
10088                                    ((old_head.column - 1) / indent_len) * indent_len,
10089                                ),
10090                            );
10091                        }
10092                    }
10093
10094                    selection.set_head(new_head, SelectionGoal::None);
10095                }
10096            }
10097
10098            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10099            this.insert("", window, cx);
10100            let empty_str: Arc<str> = Arc::from("");
10101            for (buffer, edits) in linked_ranges {
10102                let snapshot = buffer.read(cx).snapshot();
10103                use text::ToPoint as TP;
10104
10105                let edits = edits
10106                    .into_iter()
10107                    .map(|range| {
10108                        let end_point = TP::to_point(&range.end, &snapshot);
10109                        let mut start_point = TP::to_point(&range.start, &snapshot);
10110
10111                        if end_point == start_point {
10112                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10113                                .saturating_sub(1);
10114                            start_point =
10115                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10116                        };
10117
10118                        (start_point..end_point, empty_str.clone())
10119                    })
10120                    .sorted_by_key(|(range, _)| range.start)
10121                    .collect::<Vec<_>>();
10122                buffer.update(cx, |this, cx| {
10123                    this.edit(edits, None, cx);
10124                })
10125            }
10126            this.refresh_edit_prediction(true, false, window, cx);
10127            refresh_linked_ranges(this, window, cx);
10128        });
10129    }
10130
10131    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10132        if self.read_only(cx) {
10133            return;
10134        }
10135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10136        self.transact(window, cx, |this, window, cx| {
10137            this.change_selections(Default::default(), window, cx, |s| {
10138                s.move_with(|map, selection| {
10139                    if selection.is_empty() {
10140                        let cursor = movement::right(map, selection.head());
10141                        selection.end = cursor;
10142                        selection.reversed = true;
10143                        selection.goal = SelectionGoal::None;
10144                    }
10145                })
10146            });
10147            this.insert("", window, cx);
10148            this.refresh_edit_prediction(true, false, window, cx);
10149        });
10150    }
10151
10152    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10153        if self.mode.is_single_line() {
10154            cx.propagate();
10155            return;
10156        }
10157
10158        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10159        if self.move_to_prev_snippet_tabstop(window, cx) {
10160            return;
10161        }
10162        self.outdent(&Outdent, window, cx);
10163    }
10164
10165    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10166        if self.mode.is_single_line() {
10167            cx.propagate();
10168            return;
10169        }
10170
10171        if self.move_to_next_snippet_tabstop(window, cx) {
10172            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10173            return;
10174        }
10175        if self.read_only(cx) {
10176            return;
10177        }
10178        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10179        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10180        let buffer = self.buffer.read(cx);
10181        let snapshot = buffer.snapshot(cx);
10182        let rows_iter = selections.iter().map(|s| s.head().row);
10183        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10184
10185        let has_some_cursor_in_whitespace = selections
10186            .iter()
10187            .filter(|selection| selection.is_empty())
10188            .any(|selection| {
10189                let cursor = selection.head();
10190                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10191                cursor.column < current_indent.len
10192            });
10193
10194        let mut edits = Vec::new();
10195        let mut prev_edited_row = 0;
10196        let mut row_delta = 0;
10197        for selection in &mut selections {
10198            if selection.start.row != prev_edited_row {
10199                row_delta = 0;
10200            }
10201            prev_edited_row = selection.end.row;
10202
10203            // If the selection is non-empty, then increase the indentation of the selected lines.
10204            if !selection.is_empty() {
10205                row_delta =
10206                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10207                continue;
10208            }
10209
10210            let cursor = selection.head();
10211            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10212            if let Some(suggested_indent) =
10213                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10214            {
10215                // Don't do anything if already at suggested indent
10216                // and there is any other cursor which is not
10217                if has_some_cursor_in_whitespace
10218                    && cursor.column == current_indent.len
10219                    && current_indent.len == suggested_indent.len
10220                {
10221                    continue;
10222                }
10223
10224                // Adjust line and move cursor to suggested indent
10225                // if cursor is not at suggested indent
10226                if cursor.column < suggested_indent.len
10227                    && cursor.column <= current_indent.len
10228                    && current_indent.len <= suggested_indent.len
10229                {
10230                    selection.start = Point::new(cursor.row, suggested_indent.len);
10231                    selection.end = selection.start;
10232                    if row_delta == 0 {
10233                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10234                            cursor.row,
10235                            current_indent,
10236                            suggested_indent,
10237                        ));
10238                        row_delta = suggested_indent.len - current_indent.len;
10239                    }
10240                    continue;
10241                }
10242
10243                // If current indent is more than suggested indent
10244                // only move cursor to current indent and skip indent
10245                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10246                    selection.start = Point::new(cursor.row, current_indent.len);
10247                    selection.end = selection.start;
10248                    continue;
10249                }
10250            }
10251
10252            // Otherwise, insert a hard or soft tab.
10253            let settings = buffer.language_settings_at(cursor, cx);
10254            let tab_size = if settings.hard_tabs {
10255                IndentSize::tab()
10256            } else {
10257                let tab_size = settings.tab_size.get();
10258                let indent_remainder = snapshot
10259                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10260                    .flat_map(str::chars)
10261                    .fold(row_delta % tab_size, |counter: u32, c| {
10262                        if c == '\t' {
10263                            0
10264                        } else {
10265                            (counter + 1) % tab_size
10266                        }
10267                    });
10268
10269                let chars_to_next_tab_stop = tab_size - indent_remainder;
10270                IndentSize::spaces(chars_to_next_tab_stop)
10271            };
10272            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10273            selection.end = selection.start;
10274            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10275            row_delta += tab_size.len;
10276        }
10277
10278        self.transact(window, cx, |this, window, cx| {
10279            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10280            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10281            this.refresh_edit_prediction(true, false, window, cx);
10282        });
10283    }
10284
10285    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10286        if self.read_only(cx) {
10287            return;
10288        }
10289        if self.mode.is_single_line() {
10290            cx.propagate();
10291            return;
10292        }
10293
10294        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10295        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10296        let mut prev_edited_row = 0;
10297        let mut row_delta = 0;
10298        let mut edits = Vec::new();
10299        let buffer = self.buffer.read(cx);
10300        let snapshot = buffer.snapshot(cx);
10301        for selection in &mut selections {
10302            if selection.start.row != prev_edited_row {
10303                row_delta = 0;
10304            }
10305            prev_edited_row = selection.end.row;
10306
10307            row_delta =
10308                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10309        }
10310
10311        self.transact(window, cx, |this, window, cx| {
10312            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10313            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10314        });
10315    }
10316
10317    fn indent_selection(
10318        buffer: &MultiBuffer,
10319        snapshot: &MultiBufferSnapshot,
10320        selection: &mut Selection<Point>,
10321        edits: &mut Vec<(Range<Point>, String)>,
10322        delta_for_start_row: u32,
10323        cx: &App,
10324    ) -> u32 {
10325        let settings = buffer.language_settings_at(selection.start, cx);
10326        let tab_size = settings.tab_size.get();
10327        let indent_kind = if settings.hard_tabs {
10328            IndentKind::Tab
10329        } else {
10330            IndentKind::Space
10331        };
10332        let mut start_row = selection.start.row;
10333        let mut end_row = selection.end.row + 1;
10334
10335        // If a selection ends at the beginning of a line, don't indent
10336        // that last line.
10337        if selection.end.column == 0 && selection.end.row > selection.start.row {
10338            end_row -= 1;
10339        }
10340
10341        // Avoid re-indenting a row that has already been indented by a
10342        // previous selection, but still update this selection's column
10343        // to reflect that indentation.
10344        if delta_for_start_row > 0 {
10345            start_row += 1;
10346            selection.start.column += delta_for_start_row;
10347            if selection.end.row == selection.start.row {
10348                selection.end.column += delta_for_start_row;
10349            }
10350        }
10351
10352        let mut delta_for_end_row = 0;
10353        let has_multiple_rows = start_row + 1 != end_row;
10354        for row in start_row..end_row {
10355            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10356            let indent_delta = match (current_indent.kind, indent_kind) {
10357                (IndentKind::Space, IndentKind::Space) => {
10358                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10359                    IndentSize::spaces(columns_to_next_tab_stop)
10360                }
10361                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10362                (_, IndentKind::Tab) => IndentSize::tab(),
10363            };
10364
10365            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10366                0
10367            } else {
10368                selection.start.column
10369            };
10370            let row_start = Point::new(row, start);
10371            edits.push((
10372                row_start..row_start,
10373                indent_delta.chars().collect::<String>(),
10374            ));
10375
10376            // Update this selection's endpoints to reflect the indentation.
10377            if row == selection.start.row {
10378                selection.start.column += indent_delta.len;
10379            }
10380            if row == selection.end.row {
10381                selection.end.column += indent_delta.len;
10382                delta_for_end_row = indent_delta.len;
10383            }
10384        }
10385
10386        if selection.start.row == selection.end.row {
10387            delta_for_start_row + delta_for_end_row
10388        } else {
10389            delta_for_end_row
10390        }
10391    }
10392
10393    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10394        if self.read_only(cx) {
10395            return;
10396        }
10397        if self.mode.is_single_line() {
10398            cx.propagate();
10399            return;
10400        }
10401
10402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10403        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10404        let selections = self.selections.all::<Point>(&display_map);
10405        let mut deletion_ranges = Vec::new();
10406        let mut last_outdent = None;
10407        {
10408            let buffer = self.buffer.read(cx);
10409            let snapshot = buffer.snapshot(cx);
10410            for selection in &selections {
10411                let settings = buffer.language_settings_at(selection.start, cx);
10412                let tab_size = settings.tab_size.get();
10413                let mut rows = selection.spanned_rows(false, &display_map);
10414
10415                // Avoid re-outdenting a row that has already been outdented by a
10416                // previous selection.
10417                if let Some(last_row) = last_outdent
10418                    && last_row == rows.start
10419                {
10420                    rows.start = rows.start.next_row();
10421                }
10422                let has_multiple_rows = rows.len() > 1;
10423                for row in rows.iter_rows() {
10424                    let indent_size = snapshot.indent_size_for_line(row);
10425                    if indent_size.len > 0 {
10426                        let deletion_len = match indent_size.kind {
10427                            IndentKind::Space => {
10428                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10429                                if columns_to_prev_tab_stop == 0 {
10430                                    tab_size
10431                                } else {
10432                                    columns_to_prev_tab_stop
10433                                }
10434                            }
10435                            IndentKind::Tab => 1,
10436                        };
10437                        let start = if has_multiple_rows
10438                            || deletion_len > selection.start.column
10439                            || indent_size.len < selection.start.column
10440                        {
10441                            0
10442                        } else {
10443                            selection.start.column - deletion_len
10444                        };
10445                        deletion_ranges.push(
10446                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10447                        );
10448                        last_outdent = Some(row);
10449                    }
10450                }
10451            }
10452        }
10453
10454        self.transact(window, cx, |this, window, cx| {
10455            this.buffer.update(cx, |buffer, cx| {
10456                let empty_str: Arc<str> = Arc::default();
10457                buffer.edit(
10458                    deletion_ranges
10459                        .into_iter()
10460                        .map(|range| (range, empty_str.clone())),
10461                    None,
10462                    cx,
10463                );
10464            });
10465            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10466            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10467        });
10468    }
10469
10470    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10471        if self.read_only(cx) {
10472            return;
10473        }
10474        if self.mode.is_single_line() {
10475            cx.propagate();
10476            return;
10477        }
10478
10479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10480        let selections = self
10481            .selections
10482            .all::<usize>(&self.display_snapshot(cx))
10483            .into_iter()
10484            .map(|s| s.range());
10485
10486        self.transact(window, cx, |this, window, cx| {
10487            this.buffer.update(cx, |buffer, cx| {
10488                buffer.autoindent_ranges(selections, cx);
10489            });
10490            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10491            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10492        });
10493    }
10494
10495    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10496        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10497        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10498        let selections = self.selections.all::<Point>(&display_map);
10499
10500        let mut new_cursors = Vec::new();
10501        let mut edit_ranges = Vec::new();
10502        let mut selections = selections.iter().peekable();
10503        while let Some(selection) = selections.next() {
10504            let mut rows = selection.spanned_rows(false, &display_map);
10505
10506            // Accumulate contiguous regions of rows that we want to delete.
10507            while let Some(next_selection) = selections.peek() {
10508                let next_rows = next_selection.spanned_rows(false, &display_map);
10509                if next_rows.start <= rows.end {
10510                    rows.end = next_rows.end;
10511                    selections.next().unwrap();
10512                } else {
10513                    break;
10514                }
10515            }
10516
10517            let buffer = display_map.buffer_snapshot();
10518            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10519            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10520                // If there's a line after the range, delete the \n from the end of the row range
10521                (
10522                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10523                    rows.end,
10524                )
10525            } else {
10526                // If there isn't a line after the range, delete the \n from the line before the
10527                // start of the row range
10528                edit_start = edit_start.saturating_sub(1);
10529                (buffer.len(), rows.start.previous_row())
10530            };
10531
10532            let text_layout_details = self.text_layout_details(window);
10533            let x = display_map.x_for_display_point(
10534                selection.head().to_display_point(&display_map),
10535                &text_layout_details,
10536            );
10537            let row = Point::new(target_row.0, 0)
10538                .to_display_point(&display_map)
10539                .row();
10540            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10541
10542            new_cursors.push((
10543                selection.id,
10544                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10545                SelectionGoal::None,
10546            ));
10547            edit_ranges.push(edit_start..edit_end);
10548        }
10549
10550        self.transact(window, cx, |this, window, cx| {
10551            let buffer = this.buffer.update(cx, |buffer, cx| {
10552                let empty_str: Arc<str> = Arc::default();
10553                buffer.edit(
10554                    edit_ranges
10555                        .into_iter()
10556                        .map(|range| (range, empty_str.clone())),
10557                    None,
10558                    cx,
10559                );
10560                buffer.snapshot(cx)
10561            });
10562            let new_selections = new_cursors
10563                .into_iter()
10564                .map(|(id, cursor, goal)| {
10565                    let cursor = cursor.to_point(&buffer);
10566                    Selection {
10567                        id,
10568                        start: cursor,
10569                        end: cursor,
10570                        reversed: false,
10571                        goal,
10572                    }
10573                })
10574                .collect();
10575
10576            this.change_selections(Default::default(), window, cx, |s| {
10577                s.select(new_selections);
10578            });
10579        });
10580    }
10581
10582    pub fn join_lines_impl(
10583        &mut self,
10584        insert_whitespace: bool,
10585        window: &mut Window,
10586        cx: &mut Context<Self>,
10587    ) {
10588        if self.read_only(cx) {
10589            return;
10590        }
10591        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10592        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10593            let start = MultiBufferRow(selection.start.row);
10594            // Treat single line selections as if they include the next line. Otherwise this action
10595            // would do nothing for single line selections individual cursors.
10596            let end = if selection.start.row == selection.end.row {
10597                MultiBufferRow(selection.start.row + 1)
10598            } else {
10599                MultiBufferRow(selection.end.row)
10600            };
10601
10602            if let Some(last_row_range) = row_ranges.last_mut()
10603                && start <= last_row_range.end
10604            {
10605                last_row_range.end = end;
10606                continue;
10607            }
10608            row_ranges.push(start..end);
10609        }
10610
10611        let snapshot = self.buffer.read(cx).snapshot(cx);
10612        let mut cursor_positions = Vec::new();
10613        for row_range in &row_ranges {
10614            let anchor = snapshot.anchor_before(Point::new(
10615                row_range.end.previous_row().0,
10616                snapshot.line_len(row_range.end.previous_row()),
10617            ));
10618            cursor_positions.push(anchor..anchor);
10619        }
10620
10621        self.transact(window, cx, |this, window, cx| {
10622            for row_range in row_ranges.into_iter().rev() {
10623                for row in row_range.iter_rows().rev() {
10624                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10625                    let next_line_row = row.next_row();
10626                    let indent = snapshot.indent_size_for_line(next_line_row);
10627                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10628
10629                    let replace =
10630                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10631                            " "
10632                        } else {
10633                            ""
10634                        };
10635
10636                    this.buffer.update(cx, |buffer, cx| {
10637                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10638                    });
10639                }
10640            }
10641
10642            this.change_selections(Default::default(), window, cx, |s| {
10643                s.select_anchor_ranges(cursor_positions)
10644            });
10645        });
10646    }
10647
10648    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10650        self.join_lines_impl(true, window, cx);
10651    }
10652
10653    pub fn sort_lines_case_sensitive(
10654        &mut self,
10655        _: &SortLinesCaseSensitive,
10656        window: &mut Window,
10657        cx: &mut Context<Self>,
10658    ) {
10659        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10660    }
10661
10662    pub fn sort_lines_by_length(
10663        &mut self,
10664        _: &SortLinesByLength,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        self.manipulate_immutable_lines(window, cx, |lines| {
10669            lines.sort_by_key(|&line| line.chars().count())
10670        })
10671    }
10672
10673    pub fn sort_lines_case_insensitive(
10674        &mut self,
10675        _: &SortLinesCaseInsensitive,
10676        window: &mut Window,
10677        cx: &mut Context<Self>,
10678    ) {
10679        self.manipulate_immutable_lines(window, cx, |lines| {
10680            lines.sort_by_key(|line| line.to_lowercase())
10681        })
10682    }
10683
10684    pub fn unique_lines_case_insensitive(
10685        &mut self,
10686        _: &UniqueLinesCaseInsensitive,
10687        window: &mut Window,
10688        cx: &mut Context<Self>,
10689    ) {
10690        self.manipulate_immutable_lines(window, cx, |lines| {
10691            let mut seen = HashSet::default();
10692            lines.retain(|line| seen.insert(line.to_lowercase()));
10693        })
10694    }
10695
10696    pub fn unique_lines_case_sensitive(
10697        &mut self,
10698        _: &UniqueLinesCaseSensitive,
10699        window: &mut Window,
10700        cx: &mut Context<Self>,
10701    ) {
10702        self.manipulate_immutable_lines(window, cx, |lines| {
10703            let mut seen = HashSet::default();
10704            lines.retain(|line| seen.insert(*line));
10705        })
10706    }
10707
10708    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10709        let snapshot = self.buffer.read(cx).snapshot(cx);
10710        for selection in self.selections.disjoint_anchors_arc().iter() {
10711            if snapshot
10712                .language_at(selection.start)
10713                .and_then(|lang| lang.config().wrap_characters.as_ref())
10714                .is_some()
10715            {
10716                return true;
10717            }
10718        }
10719        false
10720    }
10721
10722    fn wrap_selections_in_tag(
10723        &mut self,
10724        _: &WrapSelectionsInTag,
10725        window: &mut Window,
10726        cx: &mut Context<Self>,
10727    ) {
10728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10729
10730        let snapshot = self.buffer.read(cx).snapshot(cx);
10731
10732        let mut edits = Vec::new();
10733        let mut boundaries = Vec::new();
10734
10735        for selection in self
10736            .selections
10737            .all::<Point>(&self.display_snapshot(cx))
10738            .iter()
10739        {
10740            let Some(wrap_config) = snapshot
10741                .language_at(selection.start)
10742                .and_then(|lang| lang.config().wrap_characters.clone())
10743            else {
10744                continue;
10745            };
10746
10747            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10748            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10749
10750            let start_before = snapshot.anchor_before(selection.start);
10751            let end_after = snapshot.anchor_after(selection.end);
10752
10753            edits.push((start_before..start_before, open_tag));
10754            edits.push((end_after..end_after, close_tag));
10755
10756            boundaries.push((
10757                start_before,
10758                end_after,
10759                wrap_config.start_prefix.len(),
10760                wrap_config.end_suffix.len(),
10761            ));
10762        }
10763
10764        if edits.is_empty() {
10765            return;
10766        }
10767
10768        self.transact(window, cx, |this, window, cx| {
10769            let buffer = this.buffer.update(cx, |buffer, cx| {
10770                buffer.edit(edits, None, cx);
10771                buffer.snapshot(cx)
10772            });
10773
10774            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10775            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10776                boundaries.into_iter()
10777            {
10778                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10779                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10780                new_selections.push(open_offset..open_offset);
10781                new_selections.push(close_offset..close_offset);
10782            }
10783
10784            this.change_selections(Default::default(), window, cx, |s| {
10785                s.select_ranges(new_selections);
10786            });
10787
10788            this.request_autoscroll(Autoscroll::fit(), cx);
10789        });
10790    }
10791
10792    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10793        let Some(project) = self.project.clone() else {
10794            return;
10795        };
10796        self.reload(project, window, cx)
10797            .detach_and_notify_err(window, cx);
10798    }
10799
10800    pub fn restore_file(
10801        &mut self,
10802        _: &::git::RestoreFile,
10803        window: &mut Window,
10804        cx: &mut Context<Self>,
10805    ) {
10806        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10807        let mut buffer_ids = HashSet::default();
10808        let snapshot = self.buffer().read(cx).snapshot(cx);
10809        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10810            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10811        }
10812
10813        let buffer = self.buffer().read(cx);
10814        let ranges = buffer_ids
10815            .into_iter()
10816            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10817            .collect::<Vec<_>>();
10818
10819        self.restore_hunks_in_ranges(ranges, window, cx);
10820    }
10821
10822    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10824        let selections = self
10825            .selections
10826            .all(&self.display_snapshot(cx))
10827            .into_iter()
10828            .map(|s| s.range())
10829            .collect();
10830        self.restore_hunks_in_ranges(selections, window, cx);
10831    }
10832
10833    pub fn restore_hunks_in_ranges(
10834        &mut self,
10835        ranges: Vec<Range<Point>>,
10836        window: &mut Window,
10837        cx: &mut Context<Editor>,
10838    ) {
10839        let mut revert_changes = HashMap::default();
10840        let chunk_by = self
10841            .snapshot(window, cx)
10842            .hunks_for_ranges(ranges)
10843            .into_iter()
10844            .chunk_by(|hunk| hunk.buffer_id);
10845        for (buffer_id, hunks) in &chunk_by {
10846            let hunks = hunks.collect::<Vec<_>>();
10847            for hunk in &hunks {
10848                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10849            }
10850            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10851        }
10852        drop(chunk_by);
10853        if !revert_changes.is_empty() {
10854            self.transact(window, cx, |editor, window, cx| {
10855                editor.restore(revert_changes, window, cx);
10856            });
10857        }
10858    }
10859
10860    pub fn open_active_item_in_terminal(
10861        &mut self,
10862        _: &OpenInTerminal,
10863        window: &mut Window,
10864        cx: &mut Context<Self>,
10865    ) {
10866        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10867            let project_path = buffer.read(cx).project_path(cx)?;
10868            let project = self.project()?.read(cx);
10869            let entry = project.entry_for_path(&project_path, cx)?;
10870            let parent = match &entry.canonical_path {
10871                Some(canonical_path) => canonical_path.to_path_buf(),
10872                None => project.absolute_path(&project_path, cx)?,
10873            }
10874            .parent()?
10875            .to_path_buf();
10876            Some(parent)
10877        }) {
10878            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10879        }
10880    }
10881
10882    fn set_breakpoint_context_menu(
10883        &mut self,
10884        display_row: DisplayRow,
10885        position: Option<Anchor>,
10886        clicked_point: gpui::Point<Pixels>,
10887        window: &mut Window,
10888        cx: &mut Context<Self>,
10889    ) {
10890        let source = self
10891            .buffer
10892            .read(cx)
10893            .snapshot(cx)
10894            .anchor_before(Point::new(display_row.0, 0u32));
10895
10896        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10897
10898        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10899            self,
10900            source,
10901            clicked_point,
10902            context_menu,
10903            window,
10904            cx,
10905        );
10906    }
10907
10908    fn add_edit_breakpoint_block(
10909        &mut self,
10910        anchor: Anchor,
10911        breakpoint: &Breakpoint,
10912        edit_action: BreakpointPromptEditAction,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) {
10916        let weak_editor = cx.weak_entity();
10917        let bp_prompt = cx.new(|cx| {
10918            BreakpointPromptEditor::new(
10919                weak_editor,
10920                anchor,
10921                breakpoint.clone(),
10922                edit_action,
10923                window,
10924                cx,
10925            )
10926        });
10927
10928        let height = bp_prompt.update(cx, |this, cx| {
10929            this.prompt
10930                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10931        });
10932        let cloned_prompt = bp_prompt.clone();
10933        let blocks = vec![BlockProperties {
10934            style: BlockStyle::Sticky,
10935            placement: BlockPlacement::Above(anchor),
10936            height: Some(height),
10937            render: Arc::new(move |cx| {
10938                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10939                cloned_prompt.clone().into_any_element()
10940            }),
10941            priority: 0,
10942        }];
10943
10944        let focus_handle = bp_prompt.focus_handle(cx);
10945        window.focus(&focus_handle);
10946
10947        let block_ids = self.insert_blocks(blocks, None, cx);
10948        bp_prompt.update(cx, |prompt, _| {
10949            prompt.add_block_ids(block_ids);
10950        });
10951    }
10952
10953    pub(crate) fn breakpoint_at_row(
10954        &self,
10955        row: u32,
10956        window: &mut Window,
10957        cx: &mut Context<Self>,
10958    ) -> Option<(Anchor, Breakpoint)> {
10959        let snapshot = self.snapshot(window, cx);
10960        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10961
10962        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10963    }
10964
10965    pub(crate) fn breakpoint_at_anchor(
10966        &self,
10967        breakpoint_position: Anchor,
10968        snapshot: &EditorSnapshot,
10969        cx: &mut Context<Self>,
10970    ) -> Option<(Anchor, Breakpoint)> {
10971        let buffer = self
10972            .buffer
10973            .read(cx)
10974            .buffer_for_anchor(breakpoint_position, cx)?;
10975
10976        let enclosing_excerpt = breakpoint_position.excerpt_id;
10977        let buffer_snapshot = buffer.read(cx).snapshot();
10978
10979        let row = buffer_snapshot
10980            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10981            .row;
10982
10983        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10984        let anchor_end = snapshot
10985            .buffer_snapshot()
10986            .anchor_after(Point::new(row, line_len));
10987
10988        self.breakpoint_store
10989            .as_ref()?
10990            .read_with(cx, |breakpoint_store, cx| {
10991                breakpoint_store
10992                    .breakpoints(
10993                        &buffer,
10994                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10995                        &buffer_snapshot,
10996                        cx,
10997                    )
10998                    .next()
10999                    .and_then(|(bp, _)| {
11000                        let breakpoint_row = buffer_snapshot
11001                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11002                            .row;
11003
11004                        if breakpoint_row == row {
11005                            snapshot
11006                                .buffer_snapshot()
11007                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11008                                .map(|position| (position, bp.bp.clone()))
11009                        } else {
11010                            None
11011                        }
11012                    })
11013            })
11014    }
11015
11016    pub fn edit_log_breakpoint(
11017        &mut self,
11018        _: &EditLogBreakpoint,
11019        window: &mut Window,
11020        cx: &mut Context<Self>,
11021    ) {
11022        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11023            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11024                message: None,
11025                state: BreakpointState::Enabled,
11026                condition: None,
11027                hit_condition: None,
11028            });
11029
11030            self.add_edit_breakpoint_block(
11031                anchor,
11032                &breakpoint,
11033                BreakpointPromptEditAction::Log,
11034                window,
11035                cx,
11036            );
11037        }
11038    }
11039
11040    fn breakpoints_at_cursors(
11041        &self,
11042        window: &mut Window,
11043        cx: &mut Context<Self>,
11044    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11045        let snapshot = self.snapshot(window, cx);
11046        let cursors = self
11047            .selections
11048            .disjoint_anchors_arc()
11049            .iter()
11050            .map(|selection| {
11051                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11052
11053                let breakpoint_position = self
11054                    .breakpoint_at_row(cursor_position.row, window, cx)
11055                    .map(|bp| bp.0)
11056                    .unwrap_or_else(|| {
11057                        snapshot
11058                            .display_snapshot
11059                            .buffer_snapshot()
11060                            .anchor_after(Point::new(cursor_position.row, 0))
11061                    });
11062
11063                let breakpoint = self
11064                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11065                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11066
11067                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11068            })
11069            // 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.
11070            .collect::<HashMap<Anchor, _>>();
11071
11072        cursors.into_iter().collect()
11073    }
11074
11075    pub fn enable_breakpoint(
11076        &mut self,
11077        _: &crate::actions::EnableBreakpoint,
11078        window: &mut Window,
11079        cx: &mut Context<Self>,
11080    ) {
11081        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11082            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11083                continue;
11084            };
11085            self.edit_breakpoint_at_anchor(
11086                anchor,
11087                breakpoint,
11088                BreakpointEditAction::InvertState,
11089                cx,
11090            );
11091        }
11092    }
11093
11094    pub fn disable_breakpoint(
11095        &mut self,
11096        _: &crate::actions::DisableBreakpoint,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099    ) {
11100        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11101            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11102                continue;
11103            };
11104            self.edit_breakpoint_at_anchor(
11105                anchor,
11106                breakpoint,
11107                BreakpointEditAction::InvertState,
11108                cx,
11109            );
11110        }
11111    }
11112
11113    pub fn toggle_breakpoint(
11114        &mut self,
11115        _: &crate::actions::ToggleBreakpoint,
11116        window: &mut Window,
11117        cx: &mut Context<Self>,
11118    ) {
11119        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11120            if let Some(breakpoint) = breakpoint {
11121                self.edit_breakpoint_at_anchor(
11122                    anchor,
11123                    breakpoint,
11124                    BreakpointEditAction::Toggle,
11125                    cx,
11126                );
11127            } else {
11128                self.edit_breakpoint_at_anchor(
11129                    anchor,
11130                    Breakpoint::new_standard(),
11131                    BreakpointEditAction::Toggle,
11132                    cx,
11133                );
11134            }
11135        }
11136    }
11137
11138    pub fn edit_breakpoint_at_anchor(
11139        &mut self,
11140        breakpoint_position: Anchor,
11141        breakpoint: Breakpoint,
11142        edit_action: BreakpointEditAction,
11143        cx: &mut Context<Self>,
11144    ) {
11145        let Some(breakpoint_store) = &self.breakpoint_store else {
11146            return;
11147        };
11148
11149        let Some(buffer) = self
11150            .buffer
11151            .read(cx)
11152            .buffer_for_anchor(breakpoint_position, cx)
11153        else {
11154            return;
11155        };
11156
11157        breakpoint_store.update(cx, |breakpoint_store, cx| {
11158            breakpoint_store.toggle_breakpoint(
11159                buffer,
11160                BreakpointWithPosition {
11161                    position: breakpoint_position.text_anchor,
11162                    bp: breakpoint,
11163                },
11164                edit_action,
11165                cx,
11166            );
11167        });
11168
11169        cx.notify();
11170    }
11171
11172    #[cfg(any(test, feature = "test-support"))]
11173    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11174        self.breakpoint_store.clone()
11175    }
11176
11177    pub fn prepare_restore_change(
11178        &self,
11179        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11180        hunk: &MultiBufferDiffHunk,
11181        cx: &mut App,
11182    ) -> Option<()> {
11183        if hunk.is_created_file() {
11184            return None;
11185        }
11186        let buffer = self.buffer.read(cx);
11187        let diff = buffer.diff_for(hunk.buffer_id)?;
11188        let buffer = buffer.buffer(hunk.buffer_id)?;
11189        let buffer = buffer.read(cx);
11190        let original_text = diff
11191            .read(cx)
11192            .base_text()
11193            .as_rope()
11194            .slice(hunk.diff_base_byte_range.clone());
11195        let buffer_snapshot = buffer.snapshot();
11196        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11197        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11198            probe
11199                .0
11200                .start
11201                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11202                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11203        }) {
11204            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11205            Some(())
11206        } else {
11207            None
11208        }
11209    }
11210
11211    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11212        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11213    }
11214
11215    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11216        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11217    }
11218
11219    fn manipulate_lines<M>(
11220        &mut self,
11221        window: &mut Window,
11222        cx: &mut Context<Self>,
11223        mut manipulate: M,
11224    ) where
11225        M: FnMut(&str) -> LineManipulationResult,
11226    {
11227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11228
11229        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11230        let buffer = self.buffer.read(cx).snapshot(cx);
11231
11232        let mut edits = Vec::new();
11233
11234        let selections = self.selections.all::<Point>(&display_map);
11235        let mut selections = selections.iter().peekable();
11236        let mut contiguous_row_selections = Vec::new();
11237        let mut new_selections = Vec::new();
11238        let mut added_lines = 0;
11239        let mut removed_lines = 0;
11240
11241        while let Some(selection) = selections.next() {
11242            let (start_row, end_row) = consume_contiguous_rows(
11243                &mut contiguous_row_selections,
11244                selection,
11245                &display_map,
11246                &mut selections,
11247            );
11248
11249            let start_point = Point::new(start_row.0, 0);
11250            let end_point = Point::new(
11251                end_row.previous_row().0,
11252                buffer.line_len(end_row.previous_row()),
11253            );
11254            let text = buffer
11255                .text_for_range(start_point..end_point)
11256                .collect::<String>();
11257
11258            let LineManipulationResult {
11259                new_text,
11260                line_count_before,
11261                line_count_after,
11262            } = manipulate(&text);
11263
11264            edits.push((start_point..end_point, new_text));
11265
11266            // Selections must change based on added and removed line count
11267            let start_row =
11268                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11269            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11270            new_selections.push(Selection {
11271                id: selection.id,
11272                start: start_row,
11273                end: end_row,
11274                goal: SelectionGoal::None,
11275                reversed: selection.reversed,
11276            });
11277
11278            if line_count_after > line_count_before {
11279                added_lines += line_count_after - line_count_before;
11280            } else if line_count_before > line_count_after {
11281                removed_lines += line_count_before - line_count_after;
11282            }
11283        }
11284
11285        self.transact(window, cx, |this, window, cx| {
11286            let buffer = this.buffer.update(cx, |buffer, cx| {
11287                buffer.edit(edits, None, cx);
11288                buffer.snapshot(cx)
11289            });
11290
11291            // Recalculate offsets on newly edited buffer
11292            let new_selections = new_selections
11293                .iter()
11294                .map(|s| {
11295                    let start_point = Point::new(s.start.0, 0);
11296                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11297                    Selection {
11298                        id: s.id,
11299                        start: buffer.point_to_offset(start_point),
11300                        end: buffer.point_to_offset(end_point),
11301                        goal: s.goal,
11302                        reversed: s.reversed,
11303                    }
11304                })
11305                .collect();
11306
11307            this.change_selections(Default::default(), window, cx, |s| {
11308                s.select(new_selections);
11309            });
11310
11311            this.request_autoscroll(Autoscroll::fit(), cx);
11312        });
11313    }
11314
11315    fn manipulate_immutable_lines<Fn>(
11316        &mut self,
11317        window: &mut Window,
11318        cx: &mut Context<Self>,
11319        mut callback: Fn,
11320    ) where
11321        Fn: FnMut(&mut Vec<&str>),
11322    {
11323        self.manipulate_lines(window, cx, |text| {
11324            let mut lines: Vec<&str> = text.split('\n').collect();
11325            let line_count_before = lines.len();
11326
11327            callback(&mut lines);
11328
11329            LineManipulationResult {
11330                new_text: lines.join("\n"),
11331                line_count_before,
11332                line_count_after: lines.len(),
11333            }
11334        });
11335    }
11336
11337    fn manipulate_mutable_lines<Fn>(
11338        &mut self,
11339        window: &mut Window,
11340        cx: &mut Context<Self>,
11341        mut callback: Fn,
11342    ) where
11343        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11344    {
11345        self.manipulate_lines(window, cx, |text| {
11346            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11347            let line_count_before = lines.len();
11348
11349            callback(&mut lines);
11350
11351            LineManipulationResult {
11352                new_text: lines.join("\n"),
11353                line_count_before,
11354                line_count_after: lines.len(),
11355            }
11356        });
11357    }
11358
11359    pub fn convert_indentation_to_spaces(
11360        &mut self,
11361        _: &ConvertIndentationToSpaces,
11362        window: &mut Window,
11363        cx: &mut Context<Self>,
11364    ) {
11365        let settings = self.buffer.read(cx).language_settings(cx);
11366        let tab_size = settings.tab_size.get() as usize;
11367
11368        self.manipulate_mutable_lines(window, cx, |lines| {
11369            // Allocates a reasonably sized scratch buffer once for the whole loop
11370            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11371            // Avoids recomputing spaces that could be inserted many times
11372            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11373                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11374                .collect();
11375
11376            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11377                let mut chars = line.as_ref().chars();
11378                let mut col = 0;
11379                let mut changed = false;
11380
11381                for ch in chars.by_ref() {
11382                    match ch {
11383                        ' ' => {
11384                            reindented_line.push(' ');
11385                            col += 1;
11386                        }
11387                        '\t' => {
11388                            // \t are converted to spaces depending on the current column
11389                            let spaces_len = tab_size - (col % tab_size);
11390                            reindented_line.extend(&space_cache[spaces_len - 1]);
11391                            col += spaces_len;
11392                            changed = true;
11393                        }
11394                        _ => {
11395                            // If we dont append before break, the character is consumed
11396                            reindented_line.push(ch);
11397                            break;
11398                        }
11399                    }
11400                }
11401
11402                if !changed {
11403                    reindented_line.clear();
11404                    continue;
11405                }
11406                // Append the rest of the line and replace old reference with new one
11407                reindented_line.extend(chars);
11408                *line = Cow::Owned(reindented_line.clone());
11409                reindented_line.clear();
11410            }
11411        });
11412    }
11413
11414    pub fn convert_indentation_to_tabs(
11415        &mut self,
11416        _: &ConvertIndentationToTabs,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) {
11420        let settings = self.buffer.read(cx).language_settings(cx);
11421        let tab_size = settings.tab_size.get() as usize;
11422
11423        self.manipulate_mutable_lines(window, cx, |lines| {
11424            // Allocates a reasonably sized buffer once for the whole loop
11425            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11426            // Avoids recomputing spaces that could be inserted many times
11427            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11428                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11429                .collect();
11430
11431            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11432                let mut chars = line.chars();
11433                let mut spaces_count = 0;
11434                let mut first_non_indent_char = None;
11435                let mut changed = false;
11436
11437                for ch in chars.by_ref() {
11438                    match ch {
11439                        ' ' => {
11440                            // Keep track of spaces. Append \t when we reach tab_size
11441                            spaces_count += 1;
11442                            changed = true;
11443                            if spaces_count == tab_size {
11444                                reindented_line.push('\t');
11445                                spaces_count = 0;
11446                            }
11447                        }
11448                        '\t' => {
11449                            reindented_line.push('\t');
11450                            spaces_count = 0;
11451                        }
11452                        _ => {
11453                            // Dont append it yet, we might have remaining spaces
11454                            first_non_indent_char = Some(ch);
11455                            break;
11456                        }
11457                    }
11458                }
11459
11460                if !changed {
11461                    reindented_line.clear();
11462                    continue;
11463                }
11464                // Remaining spaces that didn't make a full tab stop
11465                if spaces_count > 0 {
11466                    reindented_line.extend(&space_cache[spaces_count - 1]);
11467                }
11468                // If we consume an extra character that was not indentation, add it back
11469                if let Some(extra_char) = first_non_indent_char {
11470                    reindented_line.push(extra_char);
11471                }
11472                // Append the rest of the line and replace old reference with new one
11473                reindented_line.extend(chars);
11474                *line = Cow::Owned(reindented_line.clone());
11475                reindented_line.clear();
11476            }
11477        });
11478    }
11479
11480    pub fn convert_to_upper_case(
11481        &mut self,
11482        _: &ConvertToUpperCase,
11483        window: &mut Window,
11484        cx: &mut Context<Self>,
11485    ) {
11486        self.manipulate_text(window, cx, |text| text.to_uppercase())
11487    }
11488
11489    pub fn convert_to_lower_case(
11490        &mut self,
11491        _: &ConvertToLowerCase,
11492        window: &mut Window,
11493        cx: &mut Context<Self>,
11494    ) {
11495        self.manipulate_text(window, cx, |text| text.to_lowercase())
11496    }
11497
11498    pub fn convert_to_title_case(
11499        &mut self,
11500        _: &ConvertToTitleCase,
11501        window: &mut Window,
11502        cx: &mut Context<Self>,
11503    ) {
11504        self.manipulate_text(window, cx, |text| {
11505            text.split('\n')
11506                .map(|line| line.to_case(Case::Title))
11507                .join("\n")
11508        })
11509    }
11510
11511    pub fn convert_to_snake_case(
11512        &mut self,
11513        _: &ConvertToSnakeCase,
11514        window: &mut Window,
11515        cx: &mut Context<Self>,
11516    ) {
11517        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11518    }
11519
11520    pub fn convert_to_kebab_case(
11521        &mut self,
11522        _: &ConvertToKebabCase,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11527    }
11528
11529    pub fn convert_to_upper_camel_case(
11530        &mut self,
11531        _: &ConvertToUpperCamelCase,
11532        window: &mut Window,
11533        cx: &mut Context<Self>,
11534    ) {
11535        self.manipulate_text(window, cx, |text| {
11536            text.split('\n')
11537                .map(|line| line.to_case(Case::UpperCamel))
11538                .join("\n")
11539        })
11540    }
11541
11542    pub fn convert_to_lower_camel_case(
11543        &mut self,
11544        _: &ConvertToLowerCamelCase,
11545        window: &mut Window,
11546        cx: &mut Context<Self>,
11547    ) {
11548        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11549    }
11550
11551    pub fn convert_to_opposite_case(
11552        &mut self,
11553        _: &ConvertToOppositeCase,
11554        window: &mut Window,
11555        cx: &mut Context<Self>,
11556    ) {
11557        self.manipulate_text(window, cx, |text| {
11558            text.chars()
11559                .fold(String::with_capacity(text.len()), |mut t, c| {
11560                    if c.is_uppercase() {
11561                        t.extend(c.to_lowercase());
11562                    } else {
11563                        t.extend(c.to_uppercase());
11564                    }
11565                    t
11566                })
11567        })
11568    }
11569
11570    pub fn convert_to_sentence_case(
11571        &mut self,
11572        _: &ConvertToSentenceCase,
11573        window: &mut Window,
11574        cx: &mut Context<Self>,
11575    ) {
11576        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11577    }
11578
11579    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11580        self.manipulate_text(window, cx, |text| {
11581            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11582            if has_upper_case_characters {
11583                text.to_lowercase()
11584            } else {
11585                text.to_uppercase()
11586            }
11587        })
11588    }
11589
11590    pub fn convert_to_rot13(
11591        &mut self,
11592        _: &ConvertToRot13,
11593        window: &mut Window,
11594        cx: &mut Context<Self>,
11595    ) {
11596        self.manipulate_text(window, cx, |text| {
11597            text.chars()
11598                .map(|c| match c {
11599                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11600                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11601                    _ => c,
11602                })
11603                .collect()
11604        })
11605    }
11606
11607    pub fn convert_to_rot47(
11608        &mut self,
11609        _: &ConvertToRot47,
11610        window: &mut Window,
11611        cx: &mut Context<Self>,
11612    ) {
11613        self.manipulate_text(window, cx, |text| {
11614            text.chars()
11615                .map(|c| {
11616                    let code_point = c as u32;
11617                    if code_point >= 33 && code_point <= 126 {
11618                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11619                    }
11620                    c
11621                })
11622                .collect()
11623        })
11624    }
11625
11626    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11627    where
11628        Fn: FnMut(&str) -> String,
11629    {
11630        let buffer = self.buffer.read(cx).snapshot(cx);
11631
11632        let mut new_selections = Vec::new();
11633        let mut edits = Vec::new();
11634        let mut selection_adjustment = 0i32;
11635
11636        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11637            let selection_is_empty = selection.is_empty();
11638
11639            let (start, end) = if selection_is_empty {
11640                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11641                (word_range.start, word_range.end)
11642            } else {
11643                (
11644                    buffer.point_to_offset(selection.start),
11645                    buffer.point_to_offset(selection.end),
11646                )
11647            };
11648
11649            let text = buffer.text_for_range(start..end).collect::<String>();
11650            let old_length = text.len() as i32;
11651            let text = callback(&text);
11652
11653            new_selections.push(Selection {
11654                start: (start as i32 - selection_adjustment) as usize,
11655                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11656                goal: SelectionGoal::None,
11657                id: selection.id,
11658                reversed: selection.reversed,
11659            });
11660
11661            selection_adjustment += old_length - text.len() as i32;
11662
11663            edits.push((start..end, text));
11664        }
11665
11666        self.transact(window, cx, |this, window, cx| {
11667            this.buffer.update(cx, |buffer, cx| {
11668                buffer.edit(edits, None, cx);
11669            });
11670
11671            this.change_selections(Default::default(), window, cx, |s| {
11672                s.select(new_selections);
11673            });
11674
11675            this.request_autoscroll(Autoscroll::fit(), cx);
11676        });
11677    }
11678
11679    pub fn move_selection_on_drop(
11680        &mut self,
11681        selection: &Selection<Anchor>,
11682        target: DisplayPoint,
11683        is_cut: bool,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11688        let buffer = display_map.buffer_snapshot();
11689        let mut edits = Vec::new();
11690        let insert_point = display_map
11691            .clip_point(target, Bias::Left)
11692            .to_point(&display_map);
11693        let text = buffer
11694            .text_for_range(selection.start..selection.end)
11695            .collect::<String>();
11696        if is_cut {
11697            edits.push(((selection.start..selection.end), String::new()));
11698        }
11699        let insert_anchor = buffer.anchor_before(insert_point);
11700        edits.push(((insert_anchor..insert_anchor), text));
11701        let last_edit_start = insert_anchor.bias_left(buffer);
11702        let last_edit_end = insert_anchor.bias_right(buffer);
11703        self.transact(window, cx, |this, window, cx| {
11704            this.buffer.update(cx, |buffer, cx| {
11705                buffer.edit(edits, None, cx);
11706            });
11707            this.change_selections(Default::default(), window, cx, |s| {
11708                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11709            });
11710        });
11711    }
11712
11713    pub fn clear_selection_drag_state(&mut self) {
11714        self.selection_drag_state = SelectionDragState::None;
11715    }
11716
11717    pub fn duplicate(
11718        &mut self,
11719        upwards: bool,
11720        whole_lines: bool,
11721        window: &mut Window,
11722        cx: &mut Context<Self>,
11723    ) {
11724        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11725
11726        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11727        let buffer = display_map.buffer_snapshot();
11728        let selections = self.selections.all::<Point>(&display_map);
11729
11730        let mut edits = Vec::new();
11731        let mut selections_iter = selections.iter().peekable();
11732        while let Some(selection) = selections_iter.next() {
11733            let mut rows = selection.spanned_rows(false, &display_map);
11734            // duplicate line-wise
11735            if whole_lines || selection.start == selection.end {
11736                // Avoid duplicating the same lines twice.
11737                while let Some(next_selection) = selections_iter.peek() {
11738                    let next_rows = next_selection.spanned_rows(false, &display_map);
11739                    if next_rows.start < rows.end {
11740                        rows.end = next_rows.end;
11741                        selections_iter.next().unwrap();
11742                    } else {
11743                        break;
11744                    }
11745                }
11746
11747                // Copy the text from the selected row region and splice it either at the start
11748                // or end of the region.
11749                let start = Point::new(rows.start.0, 0);
11750                let end = Point::new(
11751                    rows.end.previous_row().0,
11752                    buffer.line_len(rows.end.previous_row()),
11753                );
11754
11755                let mut text = buffer.text_for_range(start..end).collect::<String>();
11756
11757                let insert_location = if upwards {
11758                    // When duplicating upward, we need to insert before the current line.
11759                    // If we're on the last line and it doesn't end with a newline,
11760                    // we need to add a newline before the duplicated content.
11761                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11762                        && buffer.max_point().column > 0
11763                        && !text.ends_with('\n');
11764
11765                    if needs_leading_newline {
11766                        text.insert(0, '\n');
11767                        end
11768                    } else {
11769                        text.push('\n');
11770                        Point::new(rows.end.0, 0)
11771                    }
11772                } else {
11773                    text.push('\n');
11774                    start
11775                };
11776                edits.push((insert_location..insert_location, text));
11777            } else {
11778                // duplicate character-wise
11779                let start = selection.start;
11780                let end = selection.end;
11781                let text = buffer.text_for_range(start..end).collect::<String>();
11782                edits.push((selection.end..selection.end, text));
11783            }
11784        }
11785
11786        self.transact(window, cx, |this, _, cx| {
11787            this.buffer.update(cx, |buffer, cx| {
11788                buffer.edit(edits, None, cx);
11789            });
11790
11791            this.request_autoscroll(Autoscroll::fit(), cx);
11792        });
11793    }
11794
11795    pub fn duplicate_line_up(
11796        &mut self,
11797        _: &DuplicateLineUp,
11798        window: &mut Window,
11799        cx: &mut Context<Self>,
11800    ) {
11801        self.duplicate(true, true, window, cx);
11802    }
11803
11804    pub fn duplicate_line_down(
11805        &mut self,
11806        _: &DuplicateLineDown,
11807        window: &mut Window,
11808        cx: &mut Context<Self>,
11809    ) {
11810        self.duplicate(false, true, window, cx);
11811    }
11812
11813    pub fn duplicate_selection(
11814        &mut self,
11815        _: &DuplicateSelection,
11816        window: &mut Window,
11817        cx: &mut Context<Self>,
11818    ) {
11819        self.duplicate(false, false, window, cx);
11820    }
11821
11822    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11824        if self.mode.is_single_line() {
11825            cx.propagate();
11826            return;
11827        }
11828
11829        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11830        let buffer = self.buffer.read(cx).snapshot(cx);
11831
11832        let mut edits = Vec::new();
11833        let mut unfold_ranges = Vec::new();
11834        let mut refold_creases = Vec::new();
11835
11836        let selections = self.selections.all::<Point>(&display_map);
11837        let mut selections = selections.iter().peekable();
11838        let mut contiguous_row_selections = Vec::new();
11839        let mut new_selections = Vec::new();
11840
11841        while let Some(selection) = selections.next() {
11842            // Find all the selections that span a contiguous row range
11843            let (start_row, end_row) = consume_contiguous_rows(
11844                &mut contiguous_row_selections,
11845                selection,
11846                &display_map,
11847                &mut selections,
11848            );
11849
11850            // Move the text spanned by the row range to be before the line preceding the row range
11851            if start_row.0 > 0 {
11852                let range_to_move = Point::new(
11853                    start_row.previous_row().0,
11854                    buffer.line_len(start_row.previous_row()),
11855                )
11856                    ..Point::new(
11857                        end_row.previous_row().0,
11858                        buffer.line_len(end_row.previous_row()),
11859                    );
11860                let insertion_point = display_map
11861                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11862                    .0;
11863
11864                // Don't move lines across excerpts
11865                if buffer
11866                    .excerpt_containing(insertion_point..range_to_move.end)
11867                    .is_some()
11868                {
11869                    let text = buffer
11870                        .text_for_range(range_to_move.clone())
11871                        .flat_map(|s| s.chars())
11872                        .skip(1)
11873                        .chain(['\n'])
11874                        .collect::<String>();
11875
11876                    edits.push((
11877                        buffer.anchor_after(range_to_move.start)
11878                            ..buffer.anchor_before(range_to_move.end),
11879                        String::new(),
11880                    ));
11881                    let insertion_anchor = buffer.anchor_after(insertion_point);
11882                    edits.push((insertion_anchor..insertion_anchor, text));
11883
11884                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11885
11886                    // Move selections up
11887                    new_selections.extend(contiguous_row_selections.drain(..).map(
11888                        |mut selection| {
11889                            selection.start.row -= row_delta;
11890                            selection.end.row -= row_delta;
11891                            selection
11892                        },
11893                    ));
11894
11895                    // Move folds up
11896                    unfold_ranges.push(range_to_move.clone());
11897                    for fold in display_map.folds_in_range(
11898                        buffer.anchor_before(range_to_move.start)
11899                            ..buffer.anchor_after(range_to_move.end),
11900                    ) {
11901                        let mut start = fold.range.start.to_point(&buffer);
11902                        let mut end = fold.range.end.to_point(&buffer);
11903                        start.row -= row_delta;
11904                        end.row -= row_delta;
11905                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11906                    }
11907                }
11908            }
11909
11910            // If we didn't move line(s), preserve the existing selections
11911            new_selections.append(&mut contiguous_row_selections);
11912        }
11913
11914        self.transact(window, cx, |this, window, cx| {
11915            this.unfold_ranges(&unfold_ranges, true, true, cx);
11916            this.buffer.update(cx, |buffer, cx| {
11917                for (range, text) in edits {
11918                    buffer.edit([(range, text)], None, cx);
11919                }
11920            });
11921            this.fold_creases(refold_creases, true, window, cx);
11922            this.change_selections(Default::default(), window, cx, |s| {
11923                s.select(new_selections);
11924            })
11925        });
11926    }
11927
11928    pub fn move_line_down(
11929        &mut self,
11930        _: &MoveLineDown,
11931        window: &mut Window,
11932        cx: &mut Context<Self>,
11933    ) {
11934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11935        if self.mode.is_single_line() {
11936            cx.propagate();
11937            return;
11938        }
11939
11940        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11941        let buffer = self.buffer.read(cx).snapshot(cx);
11942
11943        let mut edits = Vec::new();
11944        let mut unfold_ranges = Vec::new();
11945        let mut refold_creases = Vec::new();
11946
11947        let selections = self.selections.all::<Point>(&display_map);
11948        let mut selections = selections.iter().peekable();
11949        let mut contiguous_row_selections = Vec::new();
11950        let mut new_selections = Vec::new();
11951
11952        while let Some(selection) = selections.next() {
11953            // Find all the selections that span a contiguous row range
11954            let (start_row, end_row) = consume_contiguous_rows(
11955                &mut contiguous_row_selections,
11956                selection,
11957                &display_map,
11958                &mut selections,
11959            );
11960
11961            // Move the text spanned by the row range to be after the last line of the row range
11962            if end_row.0 <= buffer.max_point().row {
11963                let range_to_move =
11964                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11965                let insertion_point = display_map
11966                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11967                    .0;
11968
11969                // Don't move lines across excerpt boundaries
11970                if buffer
11971                    .excerpt_containing(range_to_move.start..insertion_point)
11972                    .is_some()
11973                {
11974                    let mut text = String::from("\n");
11975                    text.extend(buffer.text_for_range(range_to_move.clone()));
11976                    text.pop(); // Drop trailing newline
11977                    edits.push((
11978                        buffer.anchor_after(range_to_move.start)
11979                            ..buffer.anchor_before(range_to_move.end),
11980                        String::new(),
11981                    ));
11982                    let insertion_anchor = buffer.anchor_after(insertion_point);
11983                    edits.push((insertion_anchor..insertion_anchor, text));
11984
11985                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11986
11987                    // Move selections down
11988                    new_selections.extend(contiguous_row_selections.drain(..).map(
11989                        |mut selection| {
11990                            selection.start.row += row_delta;
11991                            selection.end.row += row_delta;
11992                            selection
11993                        },
11994                    ));
11995
11996                    // Move folds down
11997                    unfold_ranges.push(range_to_move.clone());
11998                    for fold in display_map.folds_in_range(
11999                        buffer.anchor_before(range_to_move.start)
12000                            ..buffer.anchor_after(range_to_move.end),
12001                    ) {
12002                        let mut start = fold.range.start.to_point(&buffer);
12003                        let mut end = fold.range.end.to_point(&buffer);
12004                        start.row += row_delta;
12005                        end.row += row_delta;
12006                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12007                    }
12008                }
12009            }
12010
12011            // If we didn't move line(s), preserve the existing selections
12012            new_selections.append(&mut contiguous_row_selections);
12013        }
12014
12015        self.transact(window, cx, |this, window, cx| {
12016            this.unfold_ranges(&unfold_ranges, true, true, cx);
12017            this.buffer.update(cx, |buffer, cx| {
12018                for (range, text) in edits {
12019                    buffer.edit([(range, text)], None, cx);
12020                }
12021            });
12022            this.fold_creases(refold_creases, true, window, cx);
12023            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12024        });
12025    }
12026
12027    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12029        let text_layout_details = &self.text_layout_details(window);
12030        self.transact(window, cx, |this, window, cx| {
12031            let edits = this.change_selections(Default::default(), window, cx, |s| {
12032                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12033                s.move_with(|display_map, selection| {
12034                    if !selection.is_empty() {
12035                        return;
12036                    }
12037
12038                    let mut head = selection.head();
12039                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12040                    if head.column() == display_map.line_len(head.row()) {
12041                        transpose_offset = display_map
12042                            .buffer_snapshot()
12043                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12044                    }
12045
12046                    if transpose_offset == 0 {
12047                        return;
12048                    }
12049
12050                    *head.column_mut() += 1;
12051                    head = display_map.clip_point(head, Bias::Right);
12052                    let goal = SelectionGoal::HorizontalPosition(
12053                        display_map
12054                            .x_for_display_point(head, text_layout_details)
12055                            .into(),
12056                    );
12057                    selection.collapse_to(head, goal);
12058
12059                    let transpose_start = display_map
12060                        .buffer_snapshot()
12061                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12062                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12063                        let transpose_end = display_map
12064                            .buffer_snapshot()
12065                            .clip_offset(transpose_offset + 1, Bias::Right);
12066                        if let Some(ch) = display_map
12067                            .buffer_snapshot()
12068                            .chars_at(transpose_start)
12069                            .next()
12070                        {
12071                            edits.push((transpose_start..transpose_offset, String::new()));
12072                            edits.push((transpose_end..transpose_end, ch.to_string()));
12073                        }
12074                    }
12075                });
12076                edits
12077            });
12078            this.buffer
12079                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12080            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12081            this.change_selections(Default::default(), window, cx, |s| {
12082                s.select(selections);
12083            });
12084        });
12085    }
12086
12087    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12088        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12089        if self.mode.is_single_line() {
12090            cx.propagate();
12091            return;
12092        }
12093
12094        self.rewrap_impl(RewrapOptions::default(), cx)
12095    }
12096
12097    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12098        let buffer = self.buffer.read(cx).snapshot(cx);
12099        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12100
12101        #[derive(Clone, Debug, PartialEq)]
12102        enum CommentFormat {
12103            /// single line comment, with prefix for line
12104            Line(String),
12105            /// single line within a block comment, with prefix for line
12106            BlockLine(String),
12107            /// a single line of a block comment that includes the initial delimiter
12108            BlockCommentWithStart(BlockCommentConfig),
12109            /// a single line of a block comment that includes the ending delimiter
12110            BlockCommentWithEnd(BlockCommentConfig),
12111        }
12112
12113        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12114        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12115            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12116                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12117                .peekable();
12118
12119            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12120                row
12121            } else {
12122                return Vec::new();
12123            };
12124
12125            let language_settings = buffer.language_settings_at(selection.head(), cx);
12126            let language_scope = buffer.language_scope_at(selection.head());
12127
12128            let indent_and_prefix_for_row =
12129                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12130                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12131                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12132                        &language_scope
12133                    {
12134                        let indent_end = Point::new(row, indent.len);
12135                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12136                        let line_text_after_indent = buffer
12137                            .text_for_range(indent_end..line_end)
12138                            .collect::<String>();
12139
12140                        let is_within_comment_override = buffer
12141                            .language_scope_at(indent_end)
12142                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12143                        let comment_delimiters = if is_within_comment_override {
12144                            // we are within a comment syntax node, but we don't
12145                            // yet know what kind of comment: block, doc or line
12146                            match (
12147                                language_scope.documentation_comment(),
12148                                language_scope.block_comment(),
12149                            ) {
12150                                (Some(config), _) | (_, Some(config))
12151                                    if buffer.contains_str_at(indent_end, &config.start) =>
12152                                {
12153                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12154                                }
12155                                (Some(config), _) | (_, Some(config))
12156                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12157                                {
12158                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12159                                }
12160                                (Some(config), _) | (_, Some(config))
12161                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12162                                {
12163                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12164                                }
12165                                (_, _) => language_scope
12166                                    .line_comment_prefixes()
12167                                    .iter()
12168                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12169                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12170                            }
12171                        } else {
12172                            // we not in an overridden comment node, but we may
12173                            // be within a non-overridden line comment node
12174                            language_scope
12175                                .line_comment_prefixes()
12176                                .iter()
12177                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12178                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12179                        };
12180
12181                        let rewrap_prefix = language_scope
12182                            .rewrap_prefixes()
12183                            .iter()
12184                            .find_map(|prefix_regex| {
12185                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12186                                    if mat.start() == 0 {
12187                                        Some(mat.as_str().to_string())
12188                                    } else {
12189                                        None
12190                                    }
12191                                })
12192                            })
12193                            .flatten();
12194                        (comment_delimiters, rewrap_prefix)
12195                    } else {
12196                        (None, None)
12197                    };
12198                    (indent, comment_prefix, rewrap_prefix)
12199                };
12200
12201            let mut ranges = Vec::new();
12202            let from_empty_selection = selection.is_empty();
12203
12204            let mut current_range_start = first_row;
12205            let mut prev_row = first_row;
12206            let (
12207                mut current_range_indent,
12208                mut current_range_comment_delimiters,
12209                mut current_range_rewrap_prefix,
12210            ) = indent_and_prefix_for_row(first_row);
12211
12212            for row in non_blank_rows_iter.skip(1) {
12213                let has_paragraph_break = row > prev_row + 1;
12214
12215                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12216                    indent_and_prefix_for_row(row);
12217
12218                let has_indent_change = row_indent != current_range_indent;
12219                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12220
12221                let has_boundary_change = has_comment_change
12222                    || row_rewrap_prefix.is_some()
12223                    || (has_indent_change && current_range_comment_delimiters.is_some());
12224
12225                if has_paragraph_break || has_boundary_change {
12226                    ranges.push((
12227                        language_settings.clone(),
12228                        Point::new(current_range_start, 0)
12229                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12230                        current_range_indent,
12231                        current_range_comment_delimiters.clone(),
12232                        current_range_rewrap_prefix.clone(),
12233                        from_empty_selection,
12234                    ));
12235                    current_range_start = row;
12236                    current_range_indent = row_indent;
12237                    current_range_comment_delimiters = row_comment_delimiters;
12238                    current_range_rewrap_prefix = row_rewrap_prefix;
12239                }
12240                prev_row = row;
12241            }
12242
12243            ranges.push((
12244                language_settings.clone(),
12245                Point::new(current_range_start, 0)
12246                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12247                current_range_indent,
12248                current_range_comment_delimiters,
12249                current_range_rewrap_prefix,
12250                from_empty_selection,
12251            ));
12252
12253            ranges
12254        });
12255
12256        let mut edits = Vec::new();
12257        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12258
12259        for (
12260            language_settings,
12261            wrap_range,
12262            mut indent_size,
12263            comment_prefix,
12264            rewrap_prefix,
12265            from_empty_selection,
12266        ) in wrap_ranges
12267        {
12268            let mut start_row = wrap_range.start.row;
12269            let mut end_row = wrap_range.end.row;
12270
12271            // Skip selections that overlap with a range that has already been rewrapped.
12272            let selection_range = start_row..end_row;
12273            if rewrapped_row_ranges
12274                .iter()
12275                .any(|range| range.overlaps(&selection_range))
12276            {
12277                continue;
12278            }
12279
12280            let tab_size = language_settings.tab_size;
12281
12282            let (line_prefix, inside_comment) = match &comment_prefix {
12283                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12284                    (Some(prefix.as_str()), true)
12285                }
12286                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12287                    (Some(prefix.as_ref()), true)
12288                }
12289                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12290                    start: _,
12291                    end: _,
12292                    prefix,
12293                    tab_size,
12294                })) => {
12295                    indent_size.len += tab_size;
12296                    (Some(prefix.as_ref()), true)
12297                }
12298                None => (None, false),
12299            };
12300            let indent_prefix = indent_size.chars().collect::<String>();
12301            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12302
12303            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12304                RewrapBehavior::InComments => inside_comment,
12305                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12306                RewrapBehavior::Anywhere => true,
12307            };
12308
12309            let should_rewrap = options.override_language_settings
12310                || allow_rewrap_based_on_language
12311                || self.hard_wrap.is_some();
12312            if !should_rewrap {
12313                continue;
12314            }
12315
12316            if from_empty_selection {
12317                'expand_upwards: while start_row > 0 {
12318                    let prev_row = start_row - 1;
12319                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12320                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12321                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12322                    {
12323                        start_row = prev_row;
12324                    } else {
12325                        break 'expand_upwards;
12326                    }
12327                }
12328
12329                'expand_downwards: while end_row < buffer.max_point().row {
12330                    let next_row = end_row + 1;
12331                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12332                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12333                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12334                    {
12335                        end_row = next_row;
12336                    } else {
12337                        break 'expand_downwards;
12338                    }
12339                }
12340            }
12341
12342            let start = Point::new(start_row, 0);
12343            let start_offset = ToOffset::to_offset(&start, &buffer);
12344            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12345            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12346            let mut first_line_delimiter = None;
12347            let mut last_line_delimiter = None;
12348            let Some(lines_without_prefixes) = selection_text
12349                .lines()
12350                .enumerate()
12351                .map(|(ix, line)| {
12352                    let line_trimmed = line.trim_start();
12353                    if rewrap_prefix.is_some() && ix > 0 {
12354                        Ok(line_trimmed)
12355                    } else if let Some(
12356                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12357                            start,
12358                            prefix,
12359                            end,
12360                            tab_size,
12361                        })
12362                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12363                            start,
12364                            prefix,
12365                            end,
12366                            tab_size,
12367                        }),
12368                    ) = &comment_prefix
12369                    {
12370                        let line_trimmed = line_trimmed
12371                            .strip_prefix(start.as_ref())
12372                            .map(|s| {
12373                                let mut indent_size = indent_size;
12374                                indent_size.len -= tab_size;
12375                                let indent_prefix: String = indent_size.chars().collect();
12376                                first_line_delimiter = Some((indent_prefix, start));
12377                                s.trim_start()
12378                            })
12379                            .unwrap_or(line_trimmed);
12380                        let line_trimmed = line_trimmed
12381                            .strip_suffix(end.as_ref())
12382                            .map(|s| {
12383                                last_line_delimiter = Some(end);
12384                                s.trim_end()
12385                            })
12386                            .unwrap_or(line_trimmed);
12387                        let line_trimmed = line_trimmed
12388                            .strip_prefix(prefix.as_ref())
12389                            .unwrap_or(line_trimmed);
12390                        Ok(line_trimmed)
12391                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12392                        line_trimmed.strip_prefix(prefix).with_context(|| {
12393                            format!("line did not start with prefix {prefix:?}: {line:?}")
12394                        })
12395                    } else {
12396                        line_trimmed
12397                            .strip_prefix(&line_prefix.trim_start())
12398                            .with_context(|| {
12399                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12400                            })
12401                    }
12402                })
12403                .collect::<Result<Vec<_>, _>>()
12404                .log_err()
12405            else {
12406                continue;
12407            };
12408
12409            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12410                buffer
12411                    .language_settings_at(Point::new(start_row, 0), cx)
12412                    .preferred_line_length as usize
12413            });
12414
12415            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12416                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12417            } else {
12418                line_prefix.clone()
12419            };
12420
12421            let wrapped_text = {
12422                let mut wrapped_text = wrap_with_prefix(
12423                    line_prefix,
12424                    subsequent_lines_prefix,
12425                    lines_without_prefixes.join("\n"),
12426                    wrap_column,
12427                    tab_size,
12428                    options.preserve_existing_whitespace,
12429                );
12430
12431                if let Some((indent, delimiter)) = first_line_delimiter {
12432                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12433                }
12434                if let Some(last_line) = last_line_delimiter {
12435                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12436                }
12437
12438                wrapped_text
12439            };
12440
12441            // TODO: should always use char-based diff while still supporting cursor behavior that
12442            // matches vim.
12443            let mut diff_options = DiffOptions::default();
12444            if options.override_language_settings {
12445                diff_options.max_word_diff_len = 0;
12446                diff_options.max_word_diff_line_count = 0;
12447            } else {
12448                diff_options.max_word_diff_len = usize::MAX;
12449                diff_options.max_word_diff_line_count = usize::MAX;
12450            }
12451
12452            for (old_range, new_text) in
12453                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12454            {
12455                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12456                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12457                edits.push((edit_start..edit_end, new_text));
12458            }
12459
12460            rewrapped_row_ranges.push(start_row..=end_row);
12461        }
12462
12463        self.buffer
12464            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12465    }
12466
12467    pub fn cut_common(
12468        &mut self,
12469        cut_no_selection_line: bool,
12470        window: &mut Window,
12471        cx: &mut Context<Self>,
12472    ) -> ClipboardItem {
12473        let mut text = String::new();
12474        let buffer = self.buffer.read(cx).snapshot(cx);
12475        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12476        let mut clipboard_selections = Vec::with_capacity(selections.len());
12477        {
12478            let max_point = buffer.max_point();
12479            let mut is_first = true;
12480            for selection in &mut selections {
12481                let is_entire_line =
12482                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12483                if is_entire_line {
12484                    selection.start = Point::new(selection.start.row, 0);
12485                    if !selection.is_empty() && selection.end.column == 0 {
12486                        selection.end = cmp::min(max_point, selection.end);
12487                    } else {
12488                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12489                    }
12490                    selection.goal = SelectionGoal::None;
12491                }
12492                if is_first {
12493                    is_first = false;
12494                } else {
12495                    text += "\n";
12496                }
12497                let mut len = 0;
12498                for chunk in buffer.text_for_range(selection.start..selection.end) {
12499                    text.push_str(chunk);
12500                    len += chunk.len();
12501                }
12502                clipboard_selections.push(ClipboardSelection {
12503                    len,
12504                    is_entire_line,
12505                    first_line_indent: buffer
12506                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12507                        .len,
12508                });
12509            }
12510        }
12511
12512        self.transact(window, cx, |this, window, cx| {
12513            this.change_selections(Default::default(), window, cx, |s| {
12514                s.select(selections);
12515            });
12516            this.insert("", window, cx);
12517        });
12518        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12519    }
12520
12521    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12522        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12523        let item = self.cut_common(true, window, cx);
12524        cx.write_to_clipboard(item);
12525    }
12526
12527    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12529        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12530            s.move_with(|snapshot, sel| {
12531                if sel.is_empty() {
12532                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12533                }
12534                if sel.is_empty() {
12535                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12536                }
12537            });
12538        });
12539        let item = self.cut_common(false, window, cx);
12540        cx.set_global(KillRing(item))
12541    }
12542
12543    pub fn kill_ring_yank(
12544        &mut self,
12545        _: &KillRingYank,
12546        window: &mut Window,
12547        cx: &mut Context<Self>,
12548    ) {
12549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12550        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12551            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12552                (kill_ring.text().to_string(), kill_ring.metadata_json())
12553            } else {
12554                return;
12555            }
12556        } else {
12557            return;
12558        };
12559        self.do_paste(&text, metadata, false, window, cx);
12560    }
12561
12562    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12563        self.do_copy(true, cx);
12564    }
12565
12566    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12567        self.do_copy(false, cx);
12568    }
12569
12570    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12571        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12572        let buffer = self.buffer.read(cx).read(cx);
12573        let mut text = String::new();
12574
12575        let mut clipboard_selections = Vec::with_capacity(selections.len());
12576        {
12577            let max_point = buffer.max_point();
12578            let mut is_first = true;
12579            for selection in &selections {
12580                let mut start = selection.start;
12581                let mut end = selection.end;
12582                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12583                let mut add_trailing_newline = false;
12584                if is_entire_line {
12585                    start = Point::new(start.row, 0);
12586                    let next_line_start = Point::new(end.row + 1, 0);
12587                    if next_line_start <= max_point {
12588                        end = next_line_start;
12589                    } else {
12590                        // We're on the last line without a trailing newline.
12591                        // Copy to the end of the line and add a newline afterwards.
12592                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12593                        add_trailing_newline = true;
12594                    }
12595                }
12596
12597                let mut trimmed_selections = Vec::new();
12598                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12599                    let row = MultiBufferRow(start.row);
12600                    let first_indent = buffer.indent_size_for_line(row);
12601                    if first_indent.len == 0 || start.column > first_indent.len {
12602                        trimmed_selections.push(start..end);
12603                    } else {
12604                        trimmed_selections.push(
12605                            Point::new(row.0, first_indent.len)
12606                                ..Point::new(row.0, buffer.line_len(row)),
12607                        );
12608                        for row in start.row + 1..=end.row {
12609                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12610                            if row == end.row {
12611                                line_len = end.column;
12612                            }
12613                            if line_len == 0 {
12614                                trimmed_selections
12615                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12616                                continue;
12617                            }
12618                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12619                            if row_indent_size.len >= first_indent.len {
12620                                trimmed_selections.push(
12621                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12622                                );
12623                            } else {
12624                                trimmed_selections.clear();
12625                                trimmed_selections.push(start..end);
12626                                break;
12627                            }
12628                        }
12629                    }
12630                } else {
12631                    trimmed_selections.push(start..end);
12632                }
12633
12634                for trimmed_range in trimmed_selections {
12635                    if is_first {
12636                        is_first = false;
12637                    } else {
12638                        text += "\n";
12639                    }
12640                    let mut len = 0;
12641                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12642                        text.push_str(chunk);
12643                        len += chunk.len();
12644                    }
12645                    if add_trailing_newline {
12646                        text.push('\n');
12647                        len += 1;
12648                    }
12649                    clipboard_selections.push(ClipboardSelection {
12650                        len,
12651                        is_entire_line,
12652                        first_line_indent: buffer
12653                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12654                            .len,
12655                    });
12656                }
12657            }
12658        }
12659
12660        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12661            text,
12662            clipboard_selections,
12663        ));
12664    }
12665
12666    pub fn do_paste(
12667        &mut self,
12668        text: &String,
12669        clipboard_selections: Option<Vec<ClipboardSelection>>,
12670        handle_entire_lines: bool,
12671        window: &mut Window,
12672        cx: &mut Context<Self>,
12673    ) {
12674        if self.read_only(cx) {
12675            return;
12676        }
12677
12678        let clipboard_text = Cow::Borrowed(text.as_str());
12679
12680        self.transact(window, cx, |this, window, cx| {
12681            let had_active_edit_prediction = this.has_active_edit_prediction();
12682            let display_map = this.display_snapshot(cx);
12683            let old_selections = this.selections.all::<usize>(&display_map);
12684            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12685
12686            if let Some(mut clipboard_selections) = clipboard_selections {
12687                let all_selections_were_entire_line =
12688                    clipboard_selections.iter().all(|s| s.is_entire_line);
12689                let first_selection_indent_column =
12690                    clipboard_selections.first().map(|s| s.first_line_indent);
12691                if clipboard_selections.len() != old_selections.len() {
12692                    clipboard_selections.drain(..);
12693                }
12694                let mut auto_indent_on_paste = true;
12695
12696                this.buffer.update(cx, |buffer, cx| {
12697                    let snapshot = buffer.read(cx);
12698                    auto_indent_on_paste = snapshot
12699                        .language_settings_at(cursor_offset, cx)
12700                        .auto_indent_on_paste;
12701
12702                    let mut start_offset = 0;
12703                    let mut edits = Vec::new();
12704                    let mut original_indent_columns = Vec::new();
12705                    for (ix, selection) in old_selections.iter().enumerate() {
12706                        let to_insert;
12707                        let entire_line;
12708                        let original_indent_column;
12709                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12710                            let end_offset = start_offset + clipboard_selection.len;
12711                            to_insert = &clipboard_text[start_offset..end_offset];
12712                            entire_line = clipboard_selection.is_entire_line;
12713                            start_offset = end_offset + 1;
12714                            original_indent_column = Some(clipboard_selection.first_line_indent);
12715                        } else {
12716                            to_insert = &*clipboard_text;
12717                            entire_line = all_selections_were_entire_line;
12718                            original_indent_column = first_selection_indent_column
12719                        }
12720
12721                        let (range, to_insert) =
12722                            if selection.is_empty() && handle_entire_lines && entire_line {
12723                                // If the corresponding selection was empty when this slice of the
12724                                // clipboard text was written, then the entire line containing the
12725                                // selection was copied. If this selection is also currently empty,
12726                                // then paste the line before the current line of the buffer.
12727                                let column = selection.start.to_point(&snapshot).column as usize;
12728                                let line_start = selection.start - column;
12729                                (line_start..line_start, Cow::Borrowed(to_insert))
12730                            } else {
12731                                let language = snapshot.language_at(selection.head());
12732                                let range = selection.range();
12733                                if let Some(language) = language
12734                                    && language.name() == "Markdown".into()
12735                                {
12736                                    edit_for_markdown_paste(
12737                                        &snapshot,
12738                                        range,
12739                                        to_insert,
12740                                        url::Url::parse(to_insert).ok(),
12741                                    )
12742                                } else {
12743                                    (range, Cow::Borrowed(to_insert))
12744                                }
12745                            };
12746
12747                        edits.push((range, to_insert));
12748                        original_indent_columns.push(original_indent_column);
12749                    }
12750                    drop(snapshot);
12751
12752                    buffer.edit(
12753                        edits,
12754                        if auto_indent_on_paste {
12755                            Some(AutoindentMode::Block {
12756                                original_indent_columns,
12757                            })
12758                        } else {
12759                            None
12760                        },
12761                        cx,
12762                    );
12763                });
12764
12765                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12766                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12767            } else {
12768                let url = url::Url::parse(&clipboard_text).ok();
12769
12770                let auto_indent_mode = if !clipboard_text.is_empty() {
12771                    Some(AutoindentMode::Block {
12772                        original_indent_columns: Vec::new(),
12773                    })
12774                } else {
12775                    None
12776                };
12777
12778                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12779                    let snapshot = buffer.snapshot(cx);
12780
12781                    let anchors = old_selections
12782                        .iter()
12783                        .map(|s| {
12784                            let anchor = snapshot.anchor_after(s.head());
12785                            s.map(|_| anchor)
12786                        })
12787                        .collect::<Vec<_>>();
12788
12789                    let mut edits = Vec::new();
12790
12791                    for selection in old_selections.iter() {
12792                        let language = snapshot.language_at(selection.head());
12793                        let range = selection.range();
12794
12795                        let (edit_range, edit_text) = if let Some(language) = language
12796                            && language.name() == "Markdown".into()
12797                        {
12798                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12799                        } else {
12800                            (range, clipboard_text.clone())
12801                        };
12802
12803                        edits.push((edit_range, edit_text));
12804                    }
12805
12806                    drop(snapshot);
12807                    buffer.edit(edits, auto_indent_mode, cx);
12808
12809                    anchors
12810                });
12811
12812                this.change_selections(Default::default(), window, cx, |s| {
12813                    s.select_anchors(selection_anchors);
12814                });
12815            }
12816
12817            let trigger_in_words =
12818                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12819
12820            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12821        });
12822    }
12823
12824    pub fn diff_clipboard_with_selection(
12825        &mut self,
12826        _: &DiffClipboardWithSelection,
12827        window: &mut Window,
12828        cx: &mut Context<Self>,
12829    ) {
12830        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12831
12832        if selections.is_empty() {
12833            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12834            return;
12835        };
12836
12837        let clipboard_text = match cx.read_from_clipboard() {
12838            Some(item) => match item.entries().first() {
12839                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12840                _ => None,
12841            },
12842            None => None,
12843        };
12844
12845        let Some(clipboard_text) = clipboard_text else {
12846            log::warn!("Clipboard doesn't contain text.");
12847            return;
12848        };
12849
12850        window.dispatch_action(
12851            Box::new(DiffClipboardWithSelectionData {
12852                clipboard_text,
12853                editor: cx.entity(),
12854            }),
12855            cx,
12856        );
12857    }
12858
12859    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12860        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12861        if let Some(item) = cx.read_from_clipboard() {
12862            let entries = item.entries();
12863
12864            match entries.first() {
12865                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12866                // of all the pasted entries.
12867                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12868                    .do_paste(
12869                        clipboard_string.text(),
12870                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12871                        true,
12872                        window,
12873                        cx,
12874                    ),
12875                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12876            }
12877        }
12878    }
12879
12880    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12881        if self.read_only(cx) {
12882            return;
12883        }
12884
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12886
12887        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12888            if let Some((selections, _)) =
12889                self.selection_history.transaction(transaction_id).cloned()
12890            {
12891                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12892                    s.select_anchors(selections.to_vec());
12893                });
12894            } else {
12895                log::error!(
12896                    "No entry in selection_history found for undo. \
12897                     This may correspond to a bug where undo does not update the selection. \
12898                     If this is occurring, please add details to \
12899                     https://github.com/zed-industries/zed/issues/22692"
12900                );
12901            }
12902            self.request_autoscroll(Autoscroll::fit(), cx);
12903            self.unmark_text(window, cx);
12904            self.refresh_edit_prediction(true, false, window, cx);
12905            cx.emit(EditorEvent::Edited { transaction_id });
12906            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12907        }
12908    }
12909
12910    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12911        if self.read_only(cx) {
12912            return;
12913        }
12914
12915        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12916
12917        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12918            if let Some((_, Some(selections))) =
12919                self.selection_history.transaction(transaction_id).cloned()
12920            {
12921                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12922                    s.select_anchors(selections.to_vec());
12923                });
12924            } else {
12925                log::error!(
12926                    "No entry in selection_history found for redo. \
12927                     This may correspond to a bug where undo does not update the selection. \
12928                     If this is occurring, please add details to \
12929                     https://github.com/zed-industries/zed/issues/22692"
12930                );
12931            }
12932            self.request_autoscroll(Autoscroll::fit(), cx);
12933            self.unmark_text(window, cx);
12934            self.refresh_edit_prediction(true, false, window, cx);
12935            cx.emit(EditorEvent::Edited { transaction_id });
12936        }
12937    }
12938
12939    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12940        self.buffer
12941            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12942    }
12943
12944    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12945        self.buffer
12946            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12947    }
12948
12949    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12951        self.change_selections(Default::default(), window, cx, |s| {
12952            s.move_with(|map, selection| {
12953                let cursor = if selection.is_empty() {
12954                    movement::left(map, selection.start)
12955                } else {
12956                    selection.start
12957                };
12958                selection.collapse_to(cursor, SelectionGoal::None);
12959            });
12960        })
12961    }
12962
12963    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12965        self.change_selections(Default::default(), window, cx, |s| {
12966            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12967        })
12968    }
12969
12970    pub fn move_right(&mut self, _: &MoveRight, 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::right(map, selection.end)
12976                } else {
12977                    selection.end
12978                };
12979                selection.collapse_to(cursor, SelectionGoal::None)
12980            });
12981        })
12982    }
12983
12984    pub fn select_right(&mut self, _: &SelectRight, 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::right(map, head), SelectionGoal::None));
12988        });
12989    }
12990
12991    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12992        if self.take_rename(true, window, cx).is_some() {
12993            return;
12994        }
12995
12996        if self.mode.is_single_line() {
12997            cx.propagate();
12998            return;
12999        }
13000
13001        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13002
13003        let text_layout_details = &self.text_layout_details(window);
13004        let selection_count = self.selections.count();
13005        let first_selection = self.selections.first_anchor();
13006
13007        self.change_selections(Default::default(), window, cx, |s| {
13008            s.move_with(|map, selection| {
13009                if !selection.is_empty() {
13010                    selection.goal = SelectionGoal::None;
13011                }
13012                let (cursor, goal) = movement::up(
13013                    map,
13014                    selection.start,
13015                    selection.goal,
13016                    false,
13017                    text_layout_details,
13018                );
13019                selection.collapse_to(cursor, goal);
13020            });
13021        });
13022
13023        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13024        {
13025            cx.propagate();
13026        }
13027    }
13028
13029    pub fn move_up_by_lines(
13030        &mut self,
13031        action: &MoveUpByLines,
13032        window: &mut Window,
13033        cx: &mut Context<Self>,
13034    ) {
13035        if self.take_rename(true, window, cx).is_some() {
13036            return;
13037        }
13038
13039        if self.mode.is_single_line() {
13040            cx.propagate();
13041            return;
13042        }
13043
13044        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13045
13046        let text_layout_details = &self.text_layout_details(window);
13047
13048        self.change_selections(Default::default(), window, cx, |s| {
13049            s.move_with(|map, selection| {
13050                if !selection.is_empty() {
13051                    selection.goal = SelectionGoal::None;
13052                }
13053                let (cursor, goal) = movement::up_by_rows(
13054                    map,
13055                    selection.start,
13056                    action.lines,
13057                    selection.goal,
13058                    false,
13059                    text_layout_details,
13060                );
13061                selection.collapse_to(cursor, goal);
13062            });
13063        })
13064    }
13065
13066    pub fn move_down_by_lines(
13067        &mut self,
13068        action: &MoveDownByLines,
13069        window: &mut Window,
13070        cx: &mut Context<Self>,
13071    ) {
13072        if self.take_rename(true, window, cx).is_some() {
13073            return;
13074        }
13075
13076        if self.mode.is_single_line() {
13077            cx.propagate();
13078            return;
13079        }
13080
13081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13082
13083        let text_layout_details = &self.text_layout_details(window);
13084
13085        self.change_selections(Default::default(), window, cx, |s| {
13086            s.move_with(|map, selection| {
13087                if !selection.is_empty() {
13088                    selection.goal = SelectionGoal::None;
13089                }
13090                let (cursor, goal) = movement::down_by_rows(
13091                    map,
13092                    selection.start,
13093                    action.lines,
13094                    selection.goal,
13095                    false,
13096                    text_layout_details,
13097                );
13098                selection.collapse_to(cursor, goal);
13099            });
13100        })
13101    }
13102
13103    pub fn select_down_by_lines(
13104        &mut self,
13105        action: &SelectDownByLines,
13106        window: &mut Window,
13107        cx: &mut Context<Self>,
13108    ) {
13109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13110        let text_layout_details = &self.text_layout_details(window);
13111        self.change_selections(Default::default(), window, cx, |s| {
13112            s.move_heads_with(|map, head, goal| {
13113                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13114            })
13115        })
13116    }
13117
13118    pub fn select_up_by_lines(
13119        &mut self,
13120        action: &SelectUpByLines,
13121        window: &mut Window,
13122        cx: &mut Context<Self>,
13123    ) {
13124        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13125        let text_layout_details = &self.text_layout_details(window);
13126        self.change_selections(Default::default(), window, cx, |s| {
13127            s.move_heads_with(|map, head, goal| {
13128                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13129            })
13130        })
13131    }
13132
13133    pub fn select_page_up(
13134        &mut self,
13135        _: &SelectPageUp,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) {
13139        let Some(row_count) = self.visible_row_count() else {
13140            return;
13141        };
13142
13143        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13144
13145        let text_layout_details = &self.text_layout_details(window);
13146
13147        self.change_selections(Default::default(), window, cx, |s| {
13148            s.move_heads_with(|map, head, goal| {
13149                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13150            })
13151        })
13152    }
13153
13154    pub fn move_page_up(
13155        &mut self,
13156        action: &MovePageUp,
13157        window: &mut Window,
13158        cx: &mut Context<Self>,
13159    ) {
13160        if self.take_rename(true, window, cx).is_some() {
13161            return;
13162        }
13163
13164        if self
13165            .context_menu
13166            .borrow_mut()
13167            .as_mut()
13168            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13169            .unwrap_or(false)
13170        {
13171            return;
13172        }
13173
13174        if matches!(self.mode, EditorMode::SingleLine) {
13175            cx.propagate();
13176            return;
13177        }
13178
13179        let Some(row_count) = self.visible_row_count() else {
13180            return;
13181        };
13182
13183        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13184
13185        let effects = if action.center_cursor {
13186            SelectionEffects::scroll(Autoscroll::center())
13187        } else {
13188            SelectionEffects::default()
13189        };
13190
13191        let text_layout_details = &self.text_layout_details(window);
13192
13193        self.change_selections(effects, window, cx, |s| {
13194            s.move_with(|map, selection| {
13195                if !selection.is_empty() {
13196                    selection.goal = SelectionGoal::None;
13197                }
13198                let (cursor, goal) = movement::up_by_rows(
13199                    map,
13200                    selection.end,
13201                    row_count,
13202                    selection.goal,
13203                    false,
13204                    text_layout_details,
13205                );
13206                selection.collapse_to(cursor, goal);
13207            });
13208        });
13209    }
13210
13211    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13213        let text_layout_details = &self.text_layout_details(window);
13214        self.change_selections(Default::default(), window, cx, |s| {
13215            s.move_heads_with(|map, head, goal| {
13216                movement::up(map, head, goal, false, text_layout_details)
13217            })
13218        })
13219    }
13220
13221    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13222        self.take_rename(true, window, cx);
13223
13224        if self.mode.is_single_line() {
13225            cx.propagate();
13226            return;
13227        }
13228
13229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13230
13231        let text_layout_details = &self.text_layout_details(window);
13232        let selection_count = self.selections.count();
13233        let first_selection = self.selections.first_anchor();
13234
13235        self.change_selections(Default::default(), window, cx, |s| {
13236            s.move_with(|map, selection| {
13237                if !selection.is_empty() {
13238                    selection.goal = SelectionGoal::None;
13239                }
13240                let (cursor, goal) = movement::down(
13241                    map,
13242                    selection.end,
13243                    selection.goal,
13244                    false,
13245                    text_layout_details,
13246                );
13247                selection.collapse_to(cursor, goal);
13248            });
13249        });
13250
13251        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13252        {
13253            cx.propagate();
13254        }
13255    }
13256
13257    pub fn select_page_down(
13258        &mut self,
13259        _: &SelectPageDown,
13260        window: &mut Window,
13261        cx: &mut Context<Self>,
13262    ) {
13263        let Some(row_count) = self.visible_row_count() else {
13264            return;
13265        };
13266
13267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13268
13269        let text_layout_details = &self.text_layout_details(window);
13270
13271        self.change_selections(Default::default(), window, cx, |s| {
13272            s.move_heads_with(|map, head, goal| {
13273                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13274            })
13275        })
13276    }
13277
13278    pub fn move_page_down(
13279        &mut self,
13280        action: &MovePageDown,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        if self.take_rename(true, window, cx).is_some() {
13285            return;
13286        }
13287
13288        if self
13289            .context_menu
13290            .borrow_mut()
13291            .as_mut()
13292            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13293            .unwrap_or(false)
13294        {
13295            return;
13296        }
13297
13298        if matches!(self.mode, EditorMode::SingleLine) {
13299            cx.propagate();
13300            return;
13301        }
13302
13303        let Some(row_count) = self.visible_row_count() else {
13304            return;
13305        };
13306
13307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13308
13309        let effects = if action.center_cursor {
13310            SelectionEffects::scroll(Autoscroll::center())
13311        } else {
13312            SelectionEffects::default()
13313        };
13314
13315        let text_layout_details = &self.text_layout_details(window);
13316        self.change_selections(effects, window, cx, |s| {
13317            s.move_with(|map, selection| {
13318                if !selection.is_empty() {
13319                    selection.goal = SelectionGoal::None;
13320                }
13321                let (cursor, goal) = movement::down_by_rows(
13322                    map,
13323                    selection.end,
13324                    row_count,
13325                    selection.goal,
13326                    false,
13327                    text_layout_details,
13328                );
13329                selection.collapse_to(cursor, goal);
13330            });
13331        });
13332    }
13333
13334    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13336        let text_layout_details = &self.text_layout_details(window);
13337        self.change_selections(Default::default(), window, cx, |s| {
13338            s.move_heads_with(|map, head, goal| {
13339                movement::down(map, head, goal, false, text_layout_details)
13340            })
13341        });
13342    }
13343
13344    pub fn context_menu_first(
13345        &mut self,
13346        _: &ContextMenuFirst,
13347        window: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13351            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13352        }
13353    }
13354
13355    pub fn context_menu_prev(
13356        &mut self,
13357        _: &ContextMenuPrevious,
13358        window: &mut Window,
13359        cx: &mut Context<Self>,
13360    ) {
13361        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13362            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13363        }
13364    }
13365
13366    pub fn context_menu_next(
13367        &mut self,
13368        _: &ContextMenuNext,
13369        window: &mut Window,
13370        cx: &mut Context<Self>,
13371    ) {
13372        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13373            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13374        }
13375    }
13376
13377    pub fn context_menu_last(
13378        &mut self,
13379        _: &ContextMenuLast,
13380        window: &mut Window,
13381        cx: &mut Context<Self>,
13382    ) {
13383        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13384            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13385        }
13386    }
13387
13388    pub fn signature_help_prev(
13389        &mut self,
13390        _: &SignatureHelpPrevious,
13391        _: &mut Window,
13392        cx: &mut Context<Self>,
13393    ) {
13394        if let Some(popover) = self.signature_help_state.popover_mut() {
13395            if popover.current_signature == 0 {
13396                popover.current_signature = popover.signatures.len() - 1;
13397            } else {
13398                popover.current_signature -= 1;
13399            }
13400            cx.notify();
13401        }
13402    }
13403
13404    pub fn signature_help_next(
13405        &mut self,
13406        _: &SignatureHelpNext,
13407        _: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        if let Some(popover) = self.signature_help_state.popover_mut() {
13411            if popover.current_signature + 1 == popover.signatures.len() {
13412                popover.current_signature = 0;
13413            } else {
13414                popover.current_signature += 1;
13415            }
13416            cx.notify();
13417        }
13418    }
13419
13420    pub fn move_to_previous_word_start(
13421        &mut self,
13422        _: &MoveToPreviousWordStart,
13423        window: &mut Window,
13424        cx: &mut Context<Self>,
13425    ) {
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13427        self.change_selections(Default::default(), window, cx, |s| {
13428            s.move_cursors_with(|map, head, _| {
13429                (
13430                    movement::previous_word_start(map, head),
13431                    SelectionGoal::None,
13432                )
13433            });
13434        })
13435    }
13436
13437    pub fn move_to_previous_subword_start(
13438        &mut self,
13439        _: &MoveToPreviousSubwordStart,
13440        window: &mut Window,
13441        cx: &mut Context<Self>,
13442    ) {
13443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13444        self.change_selections(Default::default(), window, cx, |s| {
13445            s.move_cursors_with(|map, head, _| {
13446                (
13447                    movement::previous_subword_start(map, head),
13448                    SelectionGoal::None,
13449                )
13450            });
13451        })
13452    }
13453
13454    pub fn select_to_previous_word_start(
13455        &mut self,
13456        _: &SelectToPreviousWordStart,
13457        window: &mut Window,
13458        cx: &mut Context<Self>,
13459    ) {
13460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13461        self.change_selections(Default::default(), window, cx, |s| {
13462            s.move_heads_with(|map, head, _| {
13463                (
13464                    movement::previous_word_start(map, head),
13465                    SelectionGoal::None,
13466                )
13467            });
13468        })
13469    }
13470
13471    pub fn select_to_previous_subword_start(
13472        &mut self,
13473        _: &SelectToPreviousSubwordStart,
13474        window: &mut Window,
13475        cx: &mut Context<Self>,
13476    ) {
13477        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13478        self.change_selections(Default::default(), window, cx, |s| {
13479            s.move_heads_with(|map, head, _| {
13480                (
13481                    movement::previous_subword_start(map, head),
13482                    SelectionGoal::None,
13483                )
13484            });
13485        })
13486    }
13487
13488    pub fn delete_to_previous_word_start(
13489        &mut self,
13490        action: &DeleteToPreviousWordStart,
13491        window: &mut Window,
13492        cx: &mut Context<Self>,
13493    ) {
13494        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13495        self.transact(window, cx, |this, window, cx| {
13496            this.select_autoclose_pair(window, cx);
13497            this.change_selections(Default::default(), window, cx, |s| {
13498                s.move_with(|map, selection| {
13499                    if selection.is_empty() {
13500                        let mut cursor = if action.ignore_newlines {
13501                            movement::previous_word_start(map, selection.head())
13502                        } else {
13503                            movement::previous_word_start_or_newline(map, selection.head())
13504                        };
13505                        cursor = movement::adjust_greedy_deletion(
13506                            map,
13507                            selection.head(),
13508                            cursor,
13509                            action.ignore_brackets,
13510                        );
13511                        selection.set_head(cursor, SelectionGoal::None);
13512                    }
13513                });
13514            });
13515            this.insert("", window, cx);
13516        });
13517    }
13518
13519    pub fn delete_to_previous_subword_start(
13520        &mut self,
13521        _: &DeleteToPreviousSubwordStart,
13522        window: &mut Window,
13523        cx: &mut Context<Self>,
13524    ) {
13525        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13526        self.transact(window, cx, |this, window, cx| {
13527            this.select_autoclose_pair(window, cx);
13528            this.change_selections(Default::default(), window, cx, |s| {
13529                s.move_with(|map, selection| {
13530                    if selection.is_empty() {
13531                        let mut cursor = movement::previous_subword_start(map, selection.head());
13532                        cursor =
13533                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13534                        selection.set_head(cursor, SelectionGoal::None);
13535                    }
13536                });
13537            });
13538            this.insert("", window, cx);
13539        });
13540    }
13541
13542    pub fn move_to_next_word_end(
13543        &mut self,
13544        _: &MoveToNextWordEnd,
13545        window: &mut Window,
13546        cx: &mut Context<Self>,
13547    ) {
13548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13549        self.change_selections(Default::default(), window, cx, |s| {
13550            s.move_cursors_with(|map, head, _| {
13551                (movement::next_word_end(map, head), SelectionGoal::None)
13552            });
13553        })
13554    }
13555
13556    pub fn move_to_next_subword_end(
13557        &mut self,
13558        _: &MoveToNextSubwordEnd,
13559        window: &mut Window,
13560        cx: &mut Context<Self>,
13561    ) {
13562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13563        self.change_selections(Default::default(), window, cx, |s| {
13564            s.move_cursors_with(|map, head, _| {
13565                (movement::next_subword_end(map, head), SelectionGoal::None)
13566            });
13567        })
13568    }
13569
13570    pub fn select_to_next_word_end(
13571        &mut self,
13572        _: &SelectToNextWordEnd,
13573        window: &mut Window,
13574        cx: &mut Context<Self>,
13575    ) {
13576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13577        self.change_selections(Default::default(), window, cx, |s| {
13578            s.move_heads_with(|map, head, _| {
13579                (movement::next_word_end(map, head), SelectionGoal::None)
13580            });
13581        })
13582    }
13583
13584    pub fn select_to_next_subword_end(
13585        &mut self,
13586        _: &SelectToNextSubwordEnd,
13587        window: &mut Window,
13588        cx: &mut Context<Self>,
13589    ) {
13590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13591        self.change_selections(Default::default(), window, cx, |s| {
13592            s.move_heads_with(|map, head, _| {
13593                (movement::next_subword_end(map, head), SelectionGoal::None)
13594            });
13595        })
13596    }
13597
13598    pub fn delete_to_next_word_end(
13599        &mut self,
13600        action: &DeleteToNextWordEnd,
13601        window: &mut Window,
13602        cx: &mut Context<Self>,
13603    ) {
13604        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13605        self.transact(window, cx, |this, window, cx| {
13606            this.change_selections(Default::default(), window, cx, |s| {
13607                s.move_with(|map, selection| {
13608                    if selection.is_empty() {
13609                        let mut cursor = if action.ignore_newlines {
13610                            movement::next_word_end(map, selection.head())
13611                        } else {
13612                            movement::next_word_end_or_newline(map, selection.head())
13613                        };
13614                        cursor = movement::adjust_greedy_deletion(
13615                            map,
13616                            selection.head(),
13617                            cursor,
13618                            action.ignore_brackets,
13619                        );
13620                        selection.set_head(cursor, SelectionGoal::None);
13621                    }
13622                });
13623            });
13624            this.insert("", window, cx);
13625        });
13626    }
13627
13628    pub fn delete_to_next_subword_end(
13629        &mut self,
13630        _: &DeleteToNextSubwordEnd,
13631        window: &mut Window,
13632        cx: &mut Context<Self>,
13633    ) {
13634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13635        self.transact(window, cx, |this, window, cx| {
13636            this.change_selections(Default::default(), window, cx, |s| {
13637                s.move_with(|map, selection| {
13638                    if selection.is_empty() {
13639                        let mut cursor = movement::next_subword_end(map, selection.head());
13640                        cursor =
13641                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13642                        selection.set_head(cursor, SelectionGoal::None);
13643                    }
13644                });
13645            });
13646            this.insert("", window, cx);
13647        });
13648    }
13649
13650    pub fn move_to_beginning_of_line(
13651        &mut self,
13652        action: &MoveToBeginningOfLine,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13657        self.change_selections(Default::default(), window, cx, |s| {
13658            s.move_cursors_with(|map, head, _| {
13659                (
13660                    movement::indented_line_beginning(
13661                        map,
13662                        head,
13663                        action.stop_at_soft_wraps,
13664                        action.stop_at_indent,
13665                    ),
13666                    SelectionGoal::None,
13667                )
13668            });
13669        })
13670    }
13671
13672    pub fn select_to_beginning_of_line(
13673        &mut self,
13674        action: &SelectToBeginningOfLine,
13675        window: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13679        self.change_selections(Default::default(), window, cx, |s| {
13680            s.move_heads_with(|map, head, _| {
13681                (
13682                    movement::indented_line_beginning(
13683                        map,
13684                        head,
13685                        action.stop_at_soft_wraps,
13686                        action.stop_at_indent,
13687                    ),
13688                    SelectionGoal::None,
13689                )
13690            });
13691        });
13692    }
13693
13694    pub fn delete_to_beginning_of_line(
13695        &mut self,
13696        action: &DeleteToBeginningOfLine,
13697        window: &mut Window,
13698        cx: &mut Context<Self>,
13699    ) {
13700        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13701        self.transact(window, cx, |this, window, cx| {
13702            this.change_selections(Default::default(), window, cx, |s| {
13703                s.move_with(|_, selection| {
13704                    selection.reversed = true;
13705                });
13706            });
13707
13708            this.select_to_beginning_of_line(
13709                &SelectToBeginningOfLine {
13710                    stop_at_soft_wraps: false,
13711                    stop_at_indent: action.stop_at_indent,
13712                },
13713                window,
13714                cx,
13715            );
13716            this.backspace(&Backspace, window, cx);
13717        });
13718    }
13719
13720    pub fn move_to_end_of_line(
13721        &mut self,
13722        action: &MoveToEndOfLine,
13723        window: &mut Window,
13724        cx: &mut Context<Self>,
13725    ) {
13726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13727        self.change_selections(Default::default(), window, cx, |s| {
13728            s.move_cursors_with(|map, head, _| {
13729                (
13730                    movement::line_end(map, head, action.stop_at_soft_wraps),
13731                    SelectionGoal::None,
13732                )
13733            });
13734        })
13735    }
13736
13737    pub fn select_to_end_of_line(
13738        &mut self,
13739        action: &SelectToEndOfLine,
13740        window: &mut Window,
13741        cx: &mut Context<Self>,
13742    ) {
13743        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13744        self.change_selections(Default::default(), window, cx, |s| {
13745            s.move_heads_with(|map, head, _| {
13746                (
13747                    movement::line_end(map, head, action.stop_at_soft_wraps),
13748                    SelectionGoal::None,
13749                )
13750            });
13751        })
13752    }
13753
13754    pub fn delete_to_end_of_line(
13755        &mut self,
13756        _: &DeleteToEndOfLine,
13757        window: &mut Window,
13758        cx: &mut Context<Self>,
13759    ) {
13760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13761        self.transact(window, cx, |this, window, cx| {
13762            this.select_to_end_of_line(
13763                &SelectToEndOfLine {
13764                    stop_at_soft_wraps: false,
13765                },
13766                window,
13767                cx,
13768            );
13769            this.delete(&Delete, window, cx);
13770        });
13771    }
13772
13773    pub fn cut_to_end_of_line(
13774        &mut self,
13775        action: &CutToEndOfLine,
13776        window: &mut Window,
13777        cx: &mut Context<Self>,
13778    ) {
13779        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13780        self.transact(window, cx, |this, window, cx| {
13781            this.select_to_end_of_line(
13782                &SelectToEndOfLine {
13783                    stop_at_soft_wraps: false,
13784                },
13785                window,
13786                cx,
13787            );
13788            if !action.stop_at_newlines {
13789                this.change_selections(Default::default(), window, cx, |s| {
13790                    s.move_with(|_, sel| {
13791                        if sel.is_empty() {
13792                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13793                        }
13794                    });
13795                });
13796            }
13797            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13798            let item = this.cut_common(false, window, cx);
13799            cx.write_to_clipboard(item);
13800        });
13801    }
13802
13803    pub fn move_to_start_of_paragraph(
13804        &mut self,
13805        _: &MoveToStartOfParagraph,
13806        window: &mut Window,
13807        cx: &mut Context<Self>,
13808    ) {
13809        if matches!(self.mode, EditorMode::SingleLine) {
13810            cx.propagate();
13811            return;
13812        }
13813        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13814        self.change_selections(Default::default(), window, cx, |s| {
13815            s.move_with(|map, selection| {
13816                selection.collapse_to(
13817                    movement::start_of_paragraph(map, selection.head(), 1),
13818                    SelectionGoal::None,
13819                )
13820            });
13821        })
13822    }
13823
13824    pub fn move_to_end_of_paragraph(
13825        &mut self,
13826        _: &MoveToEndOfParagraph,
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::end_of_paragraph(map, selection.head(), 1),
13839                    SelectionGoal::None,
13840                )
13841            });
13842        })
13843    }
13844
13845    pub fn select_to_start_of_paragraph(
13846        &mut self,
13847        _: &SelectToStartOfParagraph,
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_heads_with(|map, head, _| {
13858                (
13859                    movement::start_of_paragraph(map, head, 1),
13860                    SelectionGoal::None,
13861                )
13862            });
13863        })
13864    }
13865
13866    pub fn select_to_end_of_paragraph(
13867        &mut self,
13868        _: &SelectToEndOfParagraph,
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::end_of_paragraph(map, head, 1),
13881                    SelectionGoal::None,
13882                )
13883            });
13884        })
13885    }
13886
13887    pub fn move_to_start_of_excerpt(
13888        &mut self,
13889        _: &MoveToStartOfExcerpt,
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_with(|map, selection| {
13900                selection.collapse_to(
13901                    movement::start_of_excerpt(
13902                        map,
13903                        selection.head(),
13904                        workspace::searchable::Direction::Prev,
13905                    ),
13906                    SelectionGoal::None,
13907                )
13908            });
13909        })
13910    }
13911
13912    pub fn move_to_start_of_next_excerpt(
13913        &mut self,
13914        _: &MoveToStartOfNextExcerpt,
13915        window: &mut Window,
13916        cx: &mut Context<Self>,
13917    ) {
13918        if matches!(self.mode, EditorMode::SingleLine) {
13919            cx.propagate();
13920            return;
13921        }
13922
13923        self.change_selections(Default::default(), window, cx, |s| {
13924            s.move_with(|map, selection| {
13925                selection.collapse_to(
13926                    movement::start_of_excerpt(
13927                        map,
13928                        selection.head(),
13929                        workspace::searchable::Direction::Next,
13930                    ),
13931                    SelectionGoal::None,
13932                )
13933            });
13934        })
13935    }
13936
13937    pub fn move_to_end_of_excerpt(
13938        &mut self,
13939        _: &MoveToEndOfExcerpt,
13940        window: &mut Window,
13941        cx: &mut Context<Self>,
13942    ) {
13943        if matches!(self.mode, EditorMode::SingleLine) {
13944            cx.propagate();
13945            return;
13946        }
13947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13948        self.change_selections(Default::default(), window, cx, |s| {
13949            s.move_with(|map, selection| {
13950                selection.collapse_to(
13951                    movement::end_of_excerpt(
13952                        map,
13953                        selection.head(),
13954                        workspace::searchable::Direction::Next,
13955                    ),
13956                    SelectionGoal::None,
13957                )
13958            });
13959        })
13960    }
13961
13962    pub fn move_to_end_of_previous_excerpt(
13963        &mut self,
13964        _: &MoveToEndOfPreviousExcerpt,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        if matches!(self.mode, EditorMode::SingleLine) {
13969            cx.propagate();
13970            return;
13971        }
13972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13973        self.change_selections(Default::default(), window, cx, |s| {
13974            s.move_with(|map, selection| {
13975                selection.collapse_to(
13976                    movement::end_of_excerpt(
13977                        map,
13978                        selection.head(),
13979                        workspace::searchable::Direction::Prev,
13980                    ),
13981                    SelectionGoal::None,
13982                )
13983            });
13984        })
13985    }
13986
13987    pub fn select_to_start_of_excerpt(
13988        &mut self,
13989        _: &SelectToStartOfExcerpt,
13990        window: &mut Window,
13991        cx: &mut Context<Self>,
13992    ) {
13993        if matches!(self.mode, EditorMode::SingleLine) {
13994            cx.propagate();
13995            return;
13996        }
13997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13998        self.change_selections(Default::default(), window, cx, |s| {
13999            s.move_heads_with(|map, head, _| {
14000                (
14001                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14002                    SelectionGoal::None,
14003                )
14004            });
14005        })
14006    }
14007
14008    pub fn select_to_start_of_next_excerpt(
14009        &mut self,
14010        _: &SelectToStartOfNextExcerpt,
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::Next),
14023                    SelectionGoal::None,
14024                )
14025            });
14026        })
14027    }
14028
14029    pub fn select_to_end_of_excerpt(
14030        &mut self,
14031        _: &SelectToEndOfExcerpt,
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::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14044                    SelectionGoal::None,
14045                )
14046            });
14047        })
14048    }
14049
14050    pub fn select_to_end_of_previous_excerpt(
14051        &mut self,
14052        _: &SelectToEndOfPreviousExcerpt,
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::Prev),
14065                    SelectionGoal::None,
14066                )
14067            });
14068        })
14069    }
14070
14071    pub fn move_to_beginning(
14072        &mut self,
14073        _: &MoveToBeginning,
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.select_ranges(vec![0..0]);
14084        });
14085    }
14086
14087    pub fn select_to_beginning(
14088        &mut self,
14089        _: &SelectToBeginning,
14090        window: &mut Window,
14091        cx: &mut Context<Self>,
14092    ) {
14093        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14094        selection.set_head(Point::zero(), SelectionGoal::None);
14095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14096        self.change_selections(Default::default(), window, cx, |s| {
14097            s.select(vec![selection]);
14098        });
14099    }
14100
14101    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14102        if matches!(self.mode, EditorMode::SingleLine) {
14103            cx.propagate();
14104            return;
14105        }
14106        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14107        let cursor = self.buffer.read(cx).read(cx).len();
14108        self.change_selections(Default::default(), window, cx, |s| {
14109            s.select_ranges(vec![cursor..cursor])
14110        });
14111    }
14112
14113    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14114        self.nav_history = nav_history;
14115    }
14116
14117    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14118        self.nav_history.as_ref()
14119    }
14120
14121    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14122        self.push_to_nav_history(
14123            self.selections.newest_anchor().head(),
14124            None,
14125            false,
14126            true,
14127            cx,
14128        );
14129    }
14130
14131    fn push_to_nav_history(
14132        &mut self,
14133        cursor_anchor: Anchor,
14134        new_position: Option<Point>,
14135        is_deactivate: bool,
14136        always: bool,
14137        cx: &mut Context<Self>,
14138    ) {
14139        if let Some(nav_history) = self.nav_history.as_mut() {
14140            let buffer = self.buffer.read(cx).read(cx);
14141            let cursor_position = cursor_anchor.to_point(&buffer);
14142            let scroll_state = self.scroll_manager.anchor();
14143            let scroll_top_row = scroll_state.top_row(&buffer);
14144            drop(buffer);
14145
14146            if let Some(new_position) = new_position {
14147                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14148                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14149                    return;
14150                }
14151            }
14152
14153            nav_history.push(
14154                Some(NavigationData {
14155                    cursor_anchor,
14156                    cursor_position,
14157                    scroll_anchor: scroll_state,
14158                    scroll_top_row,
14159                }),
14160                cx,
14161            );
14162            cx.emit(EditorEvent::PushedToNavHistory {
14163                anchor: cursor_anchor,
14164                is_deactivate,
14165            })
14166        }
14167    }
14168
14169    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14171        let buffer = self.buffer.read(cx).snapshot(cx);
14172        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14173        selection.set_head(buffer.len(), SelectionGoal::None);
14174        self.change_selections(Default::default(), window, cx, |s| {
14175            s.select(vec![selection]);
14176        });
14177    }
14178
14179    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14181        let end = self.buffer.read(cx).read(cx).len();
14182        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14183            s.select_ranges(vec![0..end]);
14184        });
14185    }
14186
14187    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14189        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14190        let mut selections = self.selections.all::<Point>(&display_map);
14191        let max_point = display_map.buffer_snapshot().max_point();
14192        for selection in &mut selections {
14193            let rows = selection.spanned_rows(true, &display_map);
14194            selection.start = Point::new(rows.start.0, 0);
14195            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14196            selection.reversed = false;
14197        }
14198        self.change_selections(Default::default(), window, cx, |s| {
14199            s.select(selections);
14200        });
14201    }
14202
14203    pub fn split_selection_into_lines(
14204        &mut self,
14205        action: &SplitSelectionIntoLines,
14206        window: &mut Window,
14207        cx: &mut Context<Self>,
14208    ) {
14209        let selections = self
14210            .selections
14211            .all::<Point>(&self.display_snapshot(cx))
14212            .into_iter()
14213            .map(|selection| selection.start..selection.end)
14214            .collect::<Vec<_>>();
14215        self.unfold_ranges(&selections, true, true, cx);
14216
14217        let mut new_selection_ranges = Vec::new();
14218        {
14219            let buffer = self.buffer.read(cx).read(cx);
14220            for selection in selections {
14221                for row in selection.start.row..selection.end.row {
14222                    let line_start = Point::new(row, 0);
14223                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14224
14225                    if action.keep_selections {
14226                        // Keep the selection range for each line
14227                        let selection_start = if row == selection.start.row {
14228                            selection.start
14229                        } else {
14230                            line_start
14231                        };
14232                        new_selection_ranges.push(selection_start..line_end);
14233                    } else {
14234                        // Collapse to cursor at end of line
14235                        new_selection_ranges.push(line_end..line_end);
14236                    }
14237                }
14238
14239                let is_multiline_selection = selection.start.row != selection.end.row;
14240                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14241                // so this action feels more ergonomic when paired with other selection operations
14242                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14243                if !should_skip_last {
14244                    if action.keep_selections {
14245                        if is_multiline_selection {
14246                            let line_start = Point::new(selection.end.row, 0);
14247                            new_selection_ranges.push(line_start..selection.end);
14248                        } else {
14249                            new_selection_ranges.push(selection.start..selection.end);
14250                        }
14251                    } else {
14252                        new_selection_ranges.push(selection.end..selection.end);
14253                    }
14254                }
14255            }
14256        }
14257        self.change_selections(Default::default(), window, cx, |s| {
14258            s.select_ranges(new_selection_ranges);
14259        });
14260    }
14261
14262    pub fn add_selection_above(
14263        &mut self,
14264        action: &AddSelectionAbove,
14265        window: &mut Window,
14266        cx: &mut Context<Self>,
14267    ) {
14268        self.add_selection(true, action.skip_soft_wrap, window, cx);
14269    }
14270
14271    pub fn add_selection_below(
14272        &mut self,
14273        action: &AddSelectionBelow,
14274        window: &mut Window,
14275        cx: &mut Context<Self>,
14276    ) {
14277        self.add_selection(false, action.skip_soft_wrap, window, cx);
14278    }
14279
14280    fn add_selection(
14281        &mut self,
14282        above: bool,
14283        skip_soft_wrap: bool,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) {
14287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14288
14289        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14290        let all_selections = self.selections.all::<Point>(&display_map);
14291        let text_layout_details = self.text_layout_details(window);
14292
14293        let (mut columnar_selections, new_selections_to_columnarize) = {
14294            if let Some(state) = self.add_selections_state.as_ref() {
14295                let columnar_selection_ids: HashSet<_> = state
14296                    .groups
14297                    .iter()
14298                    .flat_map(|group| group.stack.iter())
14299                    .copied()
14300                    .collect();
14301
14302                all_selections
14303                    .into_iter()
14304                    .partition(|s| columnar_selection_ids.contains(&s.id))
14305            } else {
14306                (Vec::new(), all_selections)
14307            }
14308        };
14309
14310        let mut state = self
14311            .add_selections_state
14312            .take()
14313            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14314
14315        for selection in new_selections_to_columnarize {
14316            let range = selection.display_range(&display_map).sorted();
14317            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14318            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14319            let positions = start_x.min(end_x)..start_x.max(end_x);
14320            let mut stack = Vec::new();
14321            for row in range.start.row().0..=range.end.row().0 {
14322                if let Some(selection) = self.selections.build_columnar_selection(
14323                    &display_map,
14324                    DisplayRow(row),
14325                    &positions,
14326                    selection.reversed,
14327                    &text_layout_details,
14328                ) {
14329                    stack.push(selection.id);
14330                    columnar_selections.push(selection);
14331                }
14332            }
14333            if !stack.is_empty() {
14334                if above {
14335                    stack.reverse();
14336                }
14337                state.groups.push(AddSelectionsGroup { above, stack });
14338            }
14339        }
14340
14341        let mut final_selections = Vec::new();
14342        let end_row = if above {
14343            DisplayRow(0)
14344        } else {
14345            display_map.max_point().row()
14346        };
14347
14348        let mut last_added_item_per_group = HashMap::default();
14349        for group in state.groups.iter_mut() {
14350            if let Some(last_id) = group.stack.last() {
14351                last_added_item_per_group.insert(*last_id, group);
14352            }
14353        }
14354
14355        for selection in columnar_selections {
14356            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14357                if above == group.above {
14358                    let range = selection.display_range(&display_map).sorted();
14359                    debug_assert_eq!(range.start.row(), range.end.row());
14360                    let mut row = range.start.row();
14361                    let positions =
14362                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14363                            Pixels::from(start)..Pixels::from(end)
14364                        } else {
14365                            let start_x =
14366                                display_map.x_for_display_point(range.start, &text_layout_details);
14367                            let end_x =
14368                                display_map.x_for_display_point(range.end, &text_layout_details);
14369                            start_x.min(end_x)..start_x.max(end_x)
14370                        };
14371
14372                    let mut maybe_new_selection = None;
14373                    let direction = if above { -1 } else { 1 };
14374
14375                    while row != end_row {
14376                        if skip_soft_wrap {
14377                            row = display_map
14378                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14379                                .row();
14380                        } else if above {
14381                            row.0 -= 1;
14382                        } else {
14383                            row.0 += 1;
14384                        }
14385
14386                        if let Some(new_selection) = self.selections.build_columnar_selection(
14387                            &display_map,
14388                            row,
14389                            &positions,
14390                            selection.reversed,
14391                            &text_layout_details,
14392                        ) {
14393                            maybe_new_selection = Some(new_selection);
14394                            break;
14395                        }
14396                    }
14397
14398                    if let Some(new_selection) = maybe_new_selection {
14399                        group.stack.push(new_selection.id);
14400                        if above {
14401                            final_selections.push(new_selection);
14402                            final_selections.push(selection);
14403                        } else {
14404                            final_selections.push(selection);
14405                            final_selections.push(new_selection);
14406                        }
14407                    } else {
14408                        final_selections.push(selection);
14409                    }
14410                } else {
14411                    group.stack.pop();
14412                }
14413            } else {
14414                final_selections.push(selection);
14415            }
14416        }
14417
14418        self.change_selections(Default::default(), window, cx, |s| {
14419            s.select(final_selections);
14420        });
14421
14422        let final_selection_ids: HashSet<_> = self
14423            .selections
14424            .all::<Point>(&display_map)
14425            .iter()
14426            .map(|s| s.id)
14427            .collect();
14428        state.groups.retain_mut(|group| {
14429            // selections might get merged above so we remove invalid items from stacks
14430            group.stack.retain(|id| final_selection_ids.contains(id));
14431
14432            // single selection in stack can be treated as initial state
14433            group.stack.len() > 1
14434        });
14435
14436        if !state.groups.is_empty() {
14437            self.add_selections_state = Some(state);
14438        }
14439    }
14440
14441    fn select_match_ranges(
14442        &mut self,
14443        range: Range<usize>,
14444        reversed: bool,
14445        replace_newest: bool,
14446        auto_scroll: Option<Autoscroll>,
14447        window: &mut Window,
14448        cx: &mut Context<Editor>,
14449    ) {
14450        self.unfold_ranges(
14451            std::slice::from_ref(&range),
14452            false,
14453            auto_scroll.is_some(),
14454            cx,
14455        );
14456        let effects = if let Some(scroll) = auto_scroll {
14457            SelectionEffects::scroll(scroll)
14458        } else {
14459            SelectionEffects::no_scroll()
14460        };
14461        self.change_selections(effects, window, cx, |s| {
14462            if replace_newest {
14463                s.delete(s.newest_anchor().id);
14464            }
14465            if reversed {
14466                s.insert_range(range.end..range.start);
14467            } else {
14468                s.insert_range(range);
14469            }
14470        });
14471    }
14472
14473    pub fn select_next_match_internal(
14474        &mut self,
14475        display_map: &DisplaySnapshot,
14476        replace_newest: bool,
14477        autoscroll: Option<Autoscroll>,
14478        window: &mut Window,
14479        cx: &mut Context<Self>,
14480    ) -> Result<()> {
14481        let buffer = display_map.buffer_snapshot();
14482        let mut selections = self.selections.all::<usize>(&display_map);
14483        if let Some(mut select_next_state) = self.select_next_state.take() {
14484            let query = &select_next_state.query;
14485            if !select_next_state.done {
14486                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14487                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14488                let mut next_selected_range = None;
14489
14490                // Collect and sort selection ranges for efficient overlap checking
14491                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14492                selection_ranges.sort_by_key(|r| r.start);
14493
14494                let bytes_after_last_selection =
14495                    buffer.bytes_in_range(last_selection.end..buffer.len());
14496                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14497                let query_matches = query
14498                    .stream_find_iter(bytes_after_last_selection)
14499                    .map(|result| (last_selection.end, result))
14500                    .chain(
14501                        query
14502                            .stream_find_iter(bytes_before_first_selection)
14503                            .map(|result| (0, result)),
14504                    );
14505
14506                for (start_offset, query_match) in query_matches {
14507                    let query_match = query_match.unwrap(); // can only fail due to I/O
14508                    let offset_range =
14509                        start_offset + query_match.start()..start_offset + query_match.end();
14510
14511                    if !select_next_state.wordwise
14512                        || (!buffer.is_inside_word(offset_range.start, None)
14513                            && !buffer.is_inside_word(offset_range.end, None))
14514                    {
14515                        // Use binary search to check for overlap (O(log n))
14516                        let overlaps = selection_ranges
14517                            .binary_search_by(|range| {
14518                                if range.end <= offset_range.start {
14519                                    std::cmp::Ordering::Less
14520                                } else if range.start >= offset_range.end {
14521                                    std::cmp::Ordering::Greater
14522                                } else {
14523                                    std::cmp::Ordering::Equal
14524                                }
14525                            })
14526                            .is_ok();
14527
14528                        if !overlaps {
14529                            next_selected_range = Some(offset_range);
14530                            break;
14531                        }
14532                    }
14533                }
14534
14535                if let Some(next_selected_range) = next_selected_range {
14536                    self.select_match_ranges(
14537                        next_selected_range,
14538                        last_selection.reversed,
14539                        replace_newest,
14540                        autoscroll,
14541                        window,
14542                        cx,
14543                    );
14544                } else {
14545                    select_next_state.done = true;
14546                }
14547            }
14548
14549            self.select_next_state = Some(select_next_state);
14550        } else {
14551            let mut only_carets = true;
14552            let mut same_text_selected = true;
14553            let mut selected_text = None;
14554
14555            let mut selections_iter = selections.iter().peekable();
14556            while let Some(selection) = selections_iter.next() {
14557                if selection.start != selection.end {
14558                    only_carets = false;
14559                }
14560
14561                if same_text_selected {
14562                    if selected_text.is_none() {
14563                        selected_text =
14564                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14565                    }
14566
14567                    if let Some(next_selection) = selections_iter.peek() {
14568                        if next_selection.range().len() == selection.range().len() {
14569                            let next_selected_text = buffer
14570                                .text_for_range(next_selection.range())
14571                                .collect::<String>();
14572                            if Some(next_selected_text) != selected_text {
14573                                same_text_selected = false;
14574                                selected_text = None;
14575                            }
14576                        } else {
14577                            same_text_selected = false;
14578                            selected_text = None;
14579                        }
14580                    }
14581                }
14582            }
14583
14584            if only_carets {
14585                for selection in &mut selections {
14586                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14587                    selection.start = word_range.start;
14588                    selection.end = word_range.end;
14589                    selection.goal = SelectionGoal::None;
14590                    selection.reversed = false;
14591                    self.select_match_ranges(
14592                        selection.start..selection.end,
14593                        selection.reversed,
14594                        replace_newest,
14595                        autoscroll,
14596                        window,
14597                        cx,
14598                    );
14599                }
14600
14601                if selections.len() == 1 {
14602                    let selection = selections
14603                        .last()
14604                        .expect("ensured that there's only one selection");
14605                    let query = buffer
14606                        .text_for_range(selection.start..selection.end)
14607                        .collect::<String>();
14608                    let is_empty = query.is_empty();
14609                    let select_state = SelectNextState {
14610                        query: AhoCorasick::new(&[query])?,
14611                        wordwise: true,
14612                        done: is_empty,
14613                    };
14614                    self.select_next_state = Some(select_state);
14615                } else {
14616                    self.select_next_state = None;
14617                }
14618            } else if let Some(selected_text) = selected_text {
14619                self.select_next_state = Some(SelectNextState {
14620                    query: AhoCorasick::new(&[selected_text])?,
14621                    wordwise: false,
14622                    done: false,
14623                });
14624                self.select_next_match_internal(
14625                    display_map,
14626                    replace_newest,
14627                    autoscroll,
14628                    window,
14629                    cx,
14630                )?;
14631            }
14632        }
14633        Ok(())
14634    }
14635
14636    pub fn select_all_matches(
14637        &mut self,
14638        _action: &SelectAllMatches,
14639        window: &mut Window,
14640        cx: &mut Context<Self>,
14641    ) -> Result<()> {
14642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14643
14644        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14645
14646        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14647        let Some(select_next_state) = self.select_next_state.as_mut() else {
14648            return Ok(());
14649        };
14650        if select_next_state.done {
14651            return Ok(());
14652        }
14653
14654        let mut new_selections = Vec::new();
14655
14656        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14657        let buffer = display_map.buffer_snapshot();
14658        let query_matches = select_next_state
14659            .query
14660            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14661
14662        for query_match in query_matches.into_iter() {
14663            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14664            let offset_range = if reversed {
14665                query_match.end()..query_match.start()
14666            } else {
14667                query_match.start()..query_match.end()
14668            };
14669
14670            if !select_next_state.wordwise
14671                || (!buffer.is_inside_word(offset_range.start, None)
14672                    && !buffer.is_inside_word(offset_range.end, None))
14673            {
14674                new_selections.push(offset_range.start..offset_range.end);
14675            }
14676        }
14677
14678        select_next_state.done = true;
14679
14680        if new_selections.is_empty() {
14681            log::error!("bug: new_selections is empty in select_all_matches");
14682            return Ok(());
14683        }
14684
14685        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14686        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14687            selections.select_ranges(new_selections)
14688        });
14689
14690        Ok(())
14691    }
14692
14693    pub fn select_next(
14694        &mut self,
14695        action: &SelectNext,
14696        window: &mut Window,
14697        cx: &mut Context<Self>,
14698    ) -> Result<()> {
14699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14700        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14701        self.select_next_match_internal(
14702            &display_map,
14703            action.replace_newest,
14704            Some(Autoscroll::newest()),
14705            window,
14706            cx,
14707        )?;
14708        Ok(())
14709    }
14710
14711    pub fn select_previous(
14712        &mut self,
14713        action: &SelectPrevious,
14714        window: &mut Window,
14715        cx: &mut Context<Self>,
14716    ) -> Result<()> {
14717        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14718        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14719        let buffer = display_map.buffer_snapshot();
14720        let mut selections = self.selections.all::<usize>(&display_map);
14721        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14722            let query = &select_prev_state.query;
14723            if !select_prev_state.done {
14724                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14725                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14726                let mut next_selected_range = None;
14727                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14728                let bytes_before_last_selection =
14729                    buffer.reversed_bytes_in_range(0..last_selection.start);
14730                let bytes_after_first_selection =
14731                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14732                let query_matches = query
14733                    .stream_find_iter(bytes_before_last_selection)
14734                    .map(|result| (last_selection.start, result))
14735                    .chain(
14736                        query
14737                            .stream_find_iter(bytes_after_first_selection)
14738                            .map(|result| (buffer.len(), result)),
14739                    );
14740                for (end_offset, query_match) in query_matches {
14741                    let query_match = query_match.unwrap(); // can only fail due to I/O
14742                    let offset_range =
14743                        end_offset - query_match.end()..end_offset - query_match.start();
14744
14745                    if !select_prev_state.wordwise
14746                        || (!buffer.is_inside_word(offset_range.start, None)
14747                            && !buffer.is_inside_word(offset_range.end, None))
14748                    {
14749                        next_selected_range = Some(offset_range);
14750                        break;
14751                    }
14752                }
14753
14754                if let Some(next_selected_range) = next_selected_range {
14755                    self.select_match_ranges(
14756                        next_selected_range,
14757                        last_selection.reversed,
14758                        action.replace_newest,
14759                        Some(Autoscroll::newest()),
14760                        window,
14761                        cx,
14762                    );
14763                } else {
14764                    select_prev_state.done = true;
14765                }
14766            }
14767
14768            self.select_prev_state = Some(select_prev_state);
14769        } else {
14770            let mut only_carets = true;
14771            let mut same_text_selected = true;
14772            let mut selected_text = None;
14773
14774            let mut selections_iter = selections.iter().peekable();
14775            while let Some(selection) = selections_iter.next() {
14776                if selection.start != selection.end {
14777                    only_carets = false;
14778                }
14779
14780                if same_text_selected {
14781                    if selected_text.is_none() {
14782                        selected_text =
14783                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14784                    }
14785
14786                    if let Some(next_selection) = selections_iter.peek() {
14787                        if next_selection.range().len() == selection.range().len() {
14788                            let next_selected_text = buffer
14789                                .text_for_range(next_selection.range())
14790                                .collect::<String>();
14791                            if Some(next_selected_text) != selected_text {
14792                                same_text_selected = false;
14793                                selected_text = None;
14794                            }
14795                        } else {
14796                            same_text_selected = false;
14797                            selected_text = None;
14798                        }
14799                    }
14800                }
14801            }
14802
14803            if only_carets {
14804                for selection in &mut selections {
14805                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14806                    selection.start = word_range.start;
14807                    selection.end = word_range.end;
14808                    selection.goal = SelectionGoal::None;
14809                    selection.reversed = false;
14810                    self.select_match_ranges(
14811                        selection.start..selection.end,
14812                        selection.reversed,
14813                        action.replace_newest,
14814                        Some(Autoscroll::newest()),
14815                        window,
14816                        cx,
14817                    );
14818                }
14819                if selections.len() == 1 {
14820                    let selection = selections
14821                        .last()
14822                        .expect("ensured that there's only one selection");
14823                    let query = buffer
14824                        .text_for_range(selection.start..selection.end)
14825                        .collect::<String>();
14826                    let is_empty = query.is_empty();
14827                    let select_state = SelectNextState {
14828                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14829                        wordwise: true,
14830                        done: is_empty,
14831                    };
14832                    self.select_prev_state = Some(select_state);
14833                } else {
14834                    self.select_prev_state = None;
14835                }
14836            } else if let Some(selected_text) = selected_text {
14837                self.select_prev_state = Some(SelectNextState {
14838                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14839                    wordwise: false,
14840                    done: false,
14841                });
14842                self.select_previous(action, window, cx)?;
14843            }
14844        }
14845        Ok(())
14846    }
14847
14848    pub fn find_next_match(
14849        &mut self,
14850        _: &FindNextMatch,
14851        window: &mut Window,
14852        cx: &mut Context<Self>,
14853    ) -> Result<()> {
14854        let selections = self.selections.disjoint_anchors_arc();
14855        match selections.first() {
14856            Some(first) if selections.len() >= 2 => {
14857                self.change_selections(Default::default(), window, cx, |s| {
14858                    s.select_ranges([first.range()]);
14859                });
14860            }
14861            _ => self.select_next(
14862                &SelectNext {
14863                    replace_newest: true,
14864                },
14865                window,
14866                cx,
14867            )?,
14868        }
14869        Ok(())
14870    }
14871
14872    pub fn find_previous_match(
14873        &mut self,
14874        _: &FindPreviousMatch,
14875        window: &mut Window,
14876        cx: &mut Context<Self>,
14877    ) -> Result<()> {
14878        let selections = self.selections.disjoint_anchors_arc();
14879        match selections.last() {
14880            Some(last) if selections.len() >= 2 => {
14881                self.change_selections(Default::default(), window, cx, |s| {
14882                    s.select_ranges([last.range()]);
14883                });
14884            }
14885            _ => self.select_previous(
14886                &SelectPrevious {
14887                    replace_newest: true,
14888                },
14889                window,
14890                cx,
14891            )?,
14892        }
14893        Ok(())
14894    }
14895
14896    pub fn toggle_comments(
14897        &mut self,
14898        action: &ToggleComments,
14899        window: &mut Window,
14900        cx: &mut Context<Self>,
14901    ) {
14902        if self.read_only(cx) {
14903            return;
14904        }
14905        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14906        let text_layout_details = &self.text_layout_details(window);
14907        self.transact(window, cx, |this, window, cx| {
14908            let mut selections = this
14909                .selections
14910                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14911            let mut edits = Vec::new();
14912            let mut selection_edit_ranges = Vec::new();
14913            let mut last_toggled_row = None;
14914            let snapshot = this.buffer.read(cx).read(cx);
14915            let empty_str: Arc<str> = Arc::default();
14916            let mut suffixes_inserted = Vec::new();
14917            let ignore_indent = action.ignore_indent;
14918
14919            fn comment_prefix_range(
14920                snapshot: &MultiBufferSnapshot,
14921                row: MultiBufferRow,
14922                comment_prefix: &str,
14923                comment_prefix_whitespace: &str,
14924                ignore_indent: bool,
14925            ) -> Range<Point> {
14926                let indent_size = if ignore_indent {
14927                    0
14928                } else {
14929                    snapshot.indent_size_for_line(row).len
14930                };
14931
14932                let start = Point::new(row.0, indent_size);
14933
14934                let mut line_bytes = snapshot
14935                    .bytes_in_range(start..snapshot.max_point())
14936                    .flatten()
14937                    .copied();
14938
14939                // If this line currently begins with the line comment prefix, then record
14940                // the range containing the prefix.
14941                if line_bytes
14942                    .by_ref()
14943                    .take(comment_prefix.len())
14944                    .eq(comment_prefix.bytes())
14945                {
14946                    // Include any whitespace that matches the comment prefix.
14947                    let matching_whitespace_len = line_bytes
14948                        .zip(comment_prefix_whitespace.bytes())
14949                        .take_while(|(a, b)| a == b)
14950                        .count() as u32;
14951                    let end = Point::new(
14952                        start.row,
14953                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14954                    );
14955                    start..end
14956                } else {
14957                    start..start
14958                }
14959            }
14960
14961            fn comment_suffix_range(
14962                snapshot: &MultiBufferSnapshot,
14963                row: MultiBufferRow,
14964                comment_suffix: &str,
14965                comment_suffix_has_leading_space: bool,
14966            ) -> Range<Point> {
14967                let end = Point::new(row.0, snapshot.line_len(row));
14968                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14969
14970                let mut line_end_bytes = snapshot
14971                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14972                    .flatten()
14973                    .copied();
14974
14975                let leading_space_len = if suffix_start_column > 0
14976                    && line_end_bytes.next() == Some(b' ')
14977                    && comment_suffix_has_leading_space
14978                {
14979                    1
14980                } else {
14981                    0
14982                };
14983
14984                // If this line currently begins with the line comment prefix, then record
14985                // the range containing the prefix.
14986                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14987                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14988                    start..end
14989                } else {
14990                    end..end
14991                }
14992            }
14993
14994            // TODO: Handle selections that cross excerpts
14995            for selection in &mut selections {
14996                let start_column = snapshot
14997                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14998                    .len;
14999                let language = if let Some(language) =
15000                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15001                {
15002                    language
15003                } else {
15004                    continue;
15005                };
15006
15007                selection_edit_ranges.clear();
15008
15009                // If multiple selections contain a given row, avoid processing that
15010                // row more than once.
15011                let mut start_row = MultiBufferRow(selection.start.row);
15012                if last_toggled_row == Some(start_row) {
15013                    start_row = start_row.next_row();
15014                }
15015                let end_row =
15016                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15017                        MultiBufferRow(selection.end.row - 1)
15018                    } else {
15019                        MultiBufferRow(selection.end.row)
15020                    };
15021                last_toggled_row = Some(end_row);
15022
15023                if start_row > end_row {
15024                    continue;
15025                }
15026
15027                // If the language has line comments, toggle those.
15028                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15029
15030                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15031                if ignore_indent {
15032                    full_comment_prefixes = full_comment_prefixes
15033                        .into_iter()
15034                        .map(|s| Arc::from(s.trim_end()))
15035                        .collect();
15036                }
15037
15038                if !full_comment_prefixes.is_empty() {
15039                    let first_prefix = full_comment_prefixes
15040                        .first()
15041                        .expect("prefixes is non-empty");
15042                    let prefix_trimmed_lengths = full_comment_prefixes
15043                        .iter()
15044                        .map(|p| p.trim_end_matches(' ').len())
15045                        .collect::<SmallVec<[usize; 4]>>();
15046
15047                    let mut all_selection_lines_are_comments = true;
15048
15049                    for row in start_row.0..=end_row.0 {
15050                        let row = MultiBufferRow(row);
15051                        if start_row < end_row && snapshot.is_line_blank(row) {
15052                            continue;
15053                        }
15054
15055                        let prefix_range = full_comment_prefixes
15056                            .iter()
15057                            .zip(prefix_trimmed_lengths.iter().copied())
15058                            .map(|(prefix, trimmed_prefix_len)| {
15059                                comment_prefix_range(
15060                                    snapshot.deref(),
15061                                    row,
15062                                    &prefix[..trimmed_prefix_len],
15063                                    &prefix[trimmed_prefix_len..],
15064                                    ignore_indent,
15065                                )
15066                            })
15067                            .max_by_key(|range| range.end.column - range.start.column)
15068                            .expect("prefixes is non-empty");
15069
15070                        if prefix_range.is_empty() {
15071                            all_selection_lines_are_comments = false;
15072                        }
15073
15074                        selection_edit_ranges.push(prefix_range);
15075                    }
15076
15077                    if all_selection_lines_are_comments {
15078                        edits.extend(
15079                            selection_edit_ranges
15080                                .iter()
15081                                .cloned()
15082                                .map(|range| (range, empty_str.clone())),
15083                        );
15084                    } else {
15085                        let min_column = selection_edit_ranges
15086                            .iter()
15087                            .map(|range| range.start.column)
15088                            .min()
15089                            .unwrap_or(0);
15090                        edits.extend(selection_edit_ranges.iter().map(|range| {
15091                            let position = Point::new(range.start.row, min_column);
15092                            (position..position, first_prefix.clone())
15093                        }));
15094                    }
15095                } else if let Some(BlockCommentConfig {
15096                    start: full_comment_prefix,
15097                    end: comment_suffix,
15098                    ..
15099                }) = language.block_comment()
15100                {
15101                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15102                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15103                    let prefix_range = comment_prefix_range(
15104                        snapshot.deref(),
15105                        start_row,
15106                        comment_prefix,
15107                        comment_prefix_whitespace,
15108                        ignore_indent,
15109                    );
15110                    let suffix_range = comment_suffix_range(
15111                        snapshot.deref(),
15112                        end_row,
15113                        comment_suffix.trim_start_matches(' '),
15114                        comment_suffix.starts_with(' '),
15115                    );
15116
15117                    if prefix_range.is_empty() || suffix_range.is_empty() {
15118                        edits.push((
15119                            prefix_range.start..prefix_range.start,
15120                            full_comment_prefix.clone(),
15121                        ));
15122                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15123                        suffixes_inserted.push((end_row, comment_suffix.len()));
15124                    } else {
15125                        edits.push((prefix_range, empty_str.clone()));
15126                        edits.push((suffix_range, empty_str.clone()));
15127                    }
15128                } else {
15129                    continue;
15130                }
15131            }
15132
15133            drop(snapshot);
15134            this.buffer.update(cx, |buffer, cx| {
15135                buffer.edit(edits, None, cx);
15136            });
15137
15138            // Adjust selections so that they end before any comment suffixes that
15139            // were inserted.
15140            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15141            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15142            let snapshot = this.buffer.read(cx).read(cx);
15143            for selection in &mut selections {
15144                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15145                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15146                        Ordering::Less => {
15147                            suffixes_inserted.next();
15148                            continue;
15149                        }
15150                        Ordering::Greater => break,
15151                        Ordering::Equal => {
15152                            if selection.end.column == snapshot.line_len(row) {
15153                                if selection.is_empty() {
15154                                    selection.start.column -= suffix_len as u32;
15155                                }
15156                                selection.end.column -= suffix_len as u32;
15157                            }
15158                            break;
15159                        }
15160                    }
15161                }
15162            }
15163
15164            drop(snapshot);
15165            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15166
15167            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15168            let selections_on_single_row = selections.windows(2).all(|selections| {
15169                selections[0].start.row == selections[1].start.row
15170                    && selections[0].end.row == selections[1].end.row
15171                    && selections[0].start.row == selections[0].end.row
15172            });
15173            let selections_selecting = selections
15174                .iter()
15175                .any(|selection| selection.start != selection.end);
15176            let advance_downwards = action.advance_downwards
15177                && selections_on_single_row
15178                && !selections_selecting
15179                && !matches!(this.mode, EditorMode::SingleLine);
15180
15181            if advance_downwards {
15182                let snapshot = this.buffer.read(cx).snapshot(cx);
15183
15184                this.change_selections(Default::default(), window, cx, |s| {
15185                    s.move_cursors_with(|display_snapshot, display_point, _| {
15186                        let mut point = display_point.to_point(display_snapshot);
15187                        point.row += 1;
15188                        point = snapshot.clip_point(point, Bias::Left);
15189                        let display_point = point.to_display_point(display_snapshot);
15190                        let goal = SelectionGoal::HorizontalPosition(
15191                            display_snapshot
15192                                .x_for_display_point(display_point, text_layout_details)
15193                                .into(),
15194                        );
15195                        (display_point, goal)
15196                    })
15197                });
15198            }
15199        });
15200    }
15201
15202    pub fn select_enclosing_symbol(
15203        &mut self,
15204        _: &SelectEnclosingSymbol,
15205        window: &mut Window,
15206        cx: &mut Context<Self>,
15207    ) {
15208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15209
15210        let buffer = self.buffer.read(cx).snapshot(cx);
15211        let old_selections = self
15212            .selections
15213            .all::<usize>(&self.display_snapshot(cx))
15214            .into_boxed_slice();
15215
15216        fn update_selection(
15217            selection: &Selection<usize>,
15218            buffer_snap: &MultiBufferSnapshot,
15219        ) -> Option<Selection<usize>> {
15220            let cursor = selection.head();
15221            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15222            for symbol in symbols.iter().rev() {
15223                let start = symbol.range.start.to_offset(buffer_snap);
15224                let end = symbol.range.end.to_offset(buffer_snap);
15225                let new_range = start..end;
15226                if start < selection.start || end > selection.end {
15227                    return Some(Selection {
15228                        id: selection.id,
15229                        start: new_range.start,
15230                        end: new_range.end,
15231                        goal: SelectionGoal::None,
15232                        reversed: selection.reversed,
15233                    });
15234                }
15235            }
15236            None
15237        }
15238
15239        let mut selected_larger_symbol = false;
15240        let new_selections = old_selections
15241            .iter()
15242            .map(|selection| match update_selection(selection, &buffer) {
15243                Some(new_selection) => {
15244                    if new_selection.range() != selection.range() {
15245                        selected_larger_symbol = true;
15246                    }
15247                    new_selection
15248                }
15249                None => selection.clone(),
15250            })
15251            .collect::<Vec<_>>();
15252
15253        if selected_larger_symbol {
15254            self.change_selections(Default::default(), window, cx, |s| {
15255                s.select(new_selections);
15256            });
15257        }
15258    }
15259
15260    pub fn select_larger_syntax_node(
15261        &mut self,
15262        _: &SelectLargerSyntaxNode,
15263        window: &mut Window,
15264        cx: &mut Context<Self>,
15265    ) {
15266        let Some(visible_row_count) = self.visible_row_count() else {
15267            return;
15268        };
15269        let old_selections: Box<[_]> = self
15270            .selections
15271            .all::<usize>(&self.display_snapshot(cx))
15272            .into();
15273        if old_selections.is_empty() {
15274            return;
15275        }
15276
15277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15278
15279        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15280        let buffer = self.buffer.read(cx).snapshot(cx);
15281
15282        let mut selected_larger_node = false;
15283        let mut new_selections = old_selections
15284            .iter()
15285            .map(|selection| {
15286                let old_range = selection.start..selection.end;
15287
15288                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15289                    // manually select word at selection
15290                    if ["string_content", "inline"].contains(&node.kind()) {
15291                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15292                        // ignore if word is already selected
15293                        if !word_range.is_empty() && old_range != word_range {
15294                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15295                            // only select word if start and end point belongs to same word
15296                            if word_range == last_word_range {
15297                                selected_larger_node = true;
15298                                return Selection {
15299                                    id: selection.id,
15300                                    start: word_range.start,
15301                                    end: word_range.end,
15302                                    goal: SelectionGoal::None,
15303                                    reversed: selection.reversed,
15304                                };
15305                            }
15306                        }
15307                    }
15308                }
15309
15310                let mut new_range = old_range.clone();
15311                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15312                    new_range = range;
15313                    if !node.is_named() {
15314                        continue;
15315                    }
15316                    if !display_map.intersects_fold(new_range.start)
15317                        && !display_map.intersects_fold(new_range.end)
15318                    {
15319                        break;
15320                    }
15321                }
15322
15323                selected_larger_node |= new_range != old_range;
15324                Selection {
15325                    id: selection.id,
15326                    start: new_range.start,
15327                    end: new_range.end,
15328                    goal: SelectionGoal::None,
15329                    reversed: selection.reversed,
15330                }
15331            })
15332            .collect::<Vec<_>>();
15333
15334        if !selected_larger_node {
15335            return; // don't put this call in the history
15336        }
15337
15338        // scroll based on transformation done to the last selection created by the user
15339        let (last_old, last_new) = old_selections
15340            .last()
15341            .zip(new_selections.last().cloned())
15342            .expect("old_selections isn't empty");
15343
15344        // revert selection
15345        let is_selection_reversed = {
15346            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15347            new_selections.last_mut().expect("checked above").reversed =
15348                should_newest_selection_be_reversed;
15349            should_newest_selection_be_reversed
15350        };
15351
15352        if selected_larger_node {
15353            self.select_syntax_node_history.disable_clearing = true;
15354            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15355                s.select(new_selections.clone());
15356            });
15357            self.select_syntax_node_history.disable_clearing = false;
15358        }
15359
15360        let start_row = last_new.start.to_display_point(&display_map).row().0;
15361        let end_row = last_new.end.to_display_point(&display_map).row().0;
15362        let selection_height = end_row - start_row + 1;
15363        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15364
15365        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15366        let scroll_behavior = if fits_on_the_screen {
15367            self.request_autoscroll(Autoscroll::fit(), cx);
15368            SelectSyntaxNodeScrollBehavior::FitSelection
15369        } else if is_selection_reversed {
15370            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15371            SelectSyntaxNodeScrollBehavior::CursorTop
15372        } else {
15373            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15374            SelectSyntaxNodeScrollBehavior::CursorBottom
15375        };
15376
15377        self.select_syntax_node_history.push((
15378            old_selections,
15379            scroll_behavior,
15380            is_selection_reversed,
15381        ));
15382    }
15383
15384    pub fn select_smaller_syntax_node(
15385        &mut self,
15386        _: &SelectSmallerSyntaxNode,
15387        window: &mut Window,
15388        cx: &mut Context<Self>,
15389    ) {
15390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15391
15392        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15393            self.select_syntax_node_history.pop()
15394        {
15395            if let Some(selection) = selections.last_mut() {
15396                selection.reversed = is_selection_reversed;
15397            }
15398
15399            self.select_syntax_node_history.disable_clearing = true;
15400            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15401                s.select(selections.to_vec());
15402            });
15403            self.select_syntax_node_history.disable_clearing = false;
15404
15405            match scroll_behavior {
15406                SelectSyntaxNodeScrollBehavior::CursorTop => {
15407                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15408                }
15409                SelectSyntaxNodeScrollBehavior::FitSelection => {
15410                    self.request_autoscroll(Autoscroll::fit(), cx);
15411                }
15412                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15413                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15414                }
15415            }
15416        }
15417    }
15418
15419    pub fn unwrap_syntax_node(
15420        &mut self,
15421        _: &UnwrapSyntaxNode,
15422        window: &mut Window,
15423        cx: &mut Context<Self>,
15424    ) {
15425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15426
15427        let buffer = self.buffer.read(cx).snapshot(cx);
15428        let selections = self
15429            .selections
15430            .all::<usize>(&self.display_snapshot(cx))
15431            .into_iter()
15432            // subtracting the offset requires sorting
15433            .sorted_by_key(|i| i.start);
15434
15435        let full_edits = selections
15436            .into_iter()
15437            .filter_map(|selection| {
15438                let child = if selection.is_empty()
15439                    && let Some((_, ancestor_range)) =
15440                        buffer.syntax_ancestor(selection.start..selection.end)
15441                {
15442                    ancestor_range
15443                } else {
15444                    selection.range()
15445                };
15446
15447                let mut parent = child.clone();
15448                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15449                    parent = ancestor_range;
15450                    if parent.start < child.start || parent.end > child.end {
15451                        break;
15452                    }
15453                }
15454
15455                if parent == child {
15456                    return None;
15457                }
15458                let text = buffer.text_for_range(child).collect::<String>();
15459                Some((selection.id, parent, text))
15460            })
15461            .collect::<Vec<_>>();
15462        if full_edits.is_empty() {
15463            return;
15464        }
15465
15466        self.transact(window, cx, |this, window, cx| {
15467            this.buffer.update(cx, |buffer, cx| {
15468                buffer.edit(
15469                    full_edits
15470                        .iter()
15471                        .map(|(_, p, t)| (p.clone(), t.clone()))
15472                        .collect::<Vec<_>>(),
15473                    None,
15474                    cx,
15475                );
15476            });
15477            this.change_selections(Default::default(), window, cx, |s| {
15478                let mut offset = 0;
15479                let mut selections = vec![];
15480                for (id, parent, text) in full_edits {
15481                    let start = parent.start - offset;
15482                    offset += parent.len() - text.len();
15483                    selections.push(Selection {
15484                        id,
15485                        start,
15486                        end: start + text.len(),
15487                        reversed: false,
15488                        goal: Default::default(),
15489                    });
15490                }
15491                s.select(selections);
15492            });
15493        });
15494    }
15495
15496    pub fn select_next_syntax_node(
15497        &mut self,
15498        _: &SelectNextSyntaxNode,
15499        window: &mut Window,
15500        cx: &mut Context<Self>,
15501    ) {
15502        let old_selections: Box<[_]> = self
15503            .selections
15504            .all::<usize>(&self.display_snapshot(cx))
15505            .into();
15506        if old_selections.is_empty() {
15507            return;
15508        }
15509
15510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15511
15512        let buffer = self.buffer.read(cx).snapshot(cx);
15513        let mut selected_sibling = false;
15514
15515        let new_selections = old_selections
15516            .iter()
15517            .map(|selection| {
15518                let old_range = selection.start..selection.end;
15519
15520                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15521                    let new_range = node.byte_range();
15522                    selected_sibling = true;
15523                    Selection {
15524                        id: selection.id,
15525                        start: new_range.start,
15526                        end: new_range.end,
15527                        goal: SelectionGoal::None,
15528                        reversed: selection.reversed,
15529                    }
15530                } else {
15531                    selection.clone()
15532                }
15533            })
15534            .collect::<Vec<_>>();
15535
15536        if selected_sibling {
15537            self.change_selections(
15538                SelectionEffects::scroll(Autoscroll::fit()),
15539                window,
15540                cx,
15541                |s| {
15542                    s.select(new_selections);
15543                },
15544            );
15545        }
15546    }
15547
15548    pub fn select_prev_syntax_node(
15549        &mut self,
15550        _: &SelectPreviousSyntaxNode,
15551        window: &mut Window,
15552        cx: &mut Context<Self>,
15553    ) {
15554        let old_selections: Box<[_]> = self
15555            .selections
15556            .all::<usize>(&self.display_snapshot(cx))
15557            .into();
15558        if old_selections.is_empty() {
15559            return;
15560        }
15561
15562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15563
15564        let buffer = self.buffer.read(cx).snapshot(cx);
15565        let mut selected_sibling = false;
15566
15567        let new_selections = old_selections
15568            .iter()
15569            .map(|selection| {
15570                let old_range = selection.start..selection.end;
15571
15572                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15573                    let new_range = node.byte_range();
15574                    selected_sibling = true;
15575                    Selection {
15576                        id: selection.id,
15577                        start: new_range.start,
15578                        end: new_range.end,
15579                        goal: SelectionGoal::None,
15580                        reversed: selection.reversed,
15581                    }
15582                } else {
15583                    selection.clone()
15584                }
15585            })
15586            .collect::<Vec<_>>();
15587
15588        if selected_sibling {
15589            self.change_selections(
15590                SelectionEffects::scroll(Autoscroll::fit()),
15591                window,
15592                cx,
15593                |s| {
15594                    s.select(new_selections);
15595                },
15596            );
15597        }
15598    }
15599
15600    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15601        if !EditorSettings::get_global(cx).gutter.runnables {
15602            self.clear_tasks();
15603            return Task::ready(());
15604        }
15605        let project = self.project().map(Entity::downgrade);
15606        let task_sources = self.lsp_task_sources(cx);
15607        let multi_buffer = self.buffer.downgrade();
15608        cx.spawn_in(window, async move |editor, cx| {
15609            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15610            let Some(project) = project.and_then(|p| p.upgrade()) else {
15611                return;
15612            };
15613            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15614                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15615            }) else {
15616                return;
15617            };
15618
15619            let hide_runnables = project
15620                .update(cx, |project, _| project.is_via_collab())
15621                .unwrap_or(true);
15622            if hide_runnables {
15623                return;
15624            }
15625            let new_rows =
15626                cx.background_spawn({
15627                    let snapshot = display_snapshot.clone();
15628                    async move {
15629                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15630                    }
15631                })
15632                    .await;
15633            let Ok(lsp_tasks) =
15634                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15635            else {
15636                return;
15637            };
15638            let lsp_tasks = lsp_tasks.await;
15639
15640            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15641                lsp_tasks
15642                    .into_iter()
15643                    .flat_map(|(kind, tasks)| {
15644                        tasks.into_iter().filter_map(move |(location, task)| {
15645                            Some((kind.clone(), location?, task))
15646                        })
15647                    })
15648                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15649                        let buffer = location.target.buffer;
15650                        let buffer_snapshot = buffer.read(cx).snapshot();
15651                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15652                            |(excerpt_id, snapshot, _)| {
15653                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15654                                    display_snapshot
15655                                        .buffer_snapshot()
15656                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15657                                } else {
15658                                    None
15659                                }
15660                            },
15661                        );
15662                        if let Some(offset) = offset {
15663                            let task_buffer_range =
15664                                location.target.range.to_point(&buffer_snapshot);
15665                            let context_buffer_range =
15666                                task_buffer_range.to_offset(&buffer_snapshot);
15667                            let context_range = BufferOffset(context_buffer_range.start)
15668                                ..BufferOffset(context_buffer_range.end);
15669
15670                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15671                                .or_insert_with(|| RunnableTasks {
15672                                    templates: Vec::new(),
15673                                    offset,
15674                                    column: task_buffer_range.start.column,
15675                                    extra_variables: HashMap::default(),
15676                                    context_range,
15677                                })
15678                                .templates
15679                                .push((kind, task.original_task().clone()));
15680                        }
15681
15682                        acc
15683                    })
15684            }) else {
15685                return;
15686            };
15687
15688            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15689                buffer.language_settings(cx).tasks.prefer_lsp
15690            }) else {
15691                return;
15692            };
15693
15694            let rows = Self::runnable_rows(
15695                project,
15696                display_snapshot,
15697                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15698                new_rows,
15699                cx.clone(),
15700            )
15701            .await;
15702            editor
15703                .update(cx, |editor, _| {
15704                    editor.clear_tasks();
15705                    for (key, mut value) in rows {
15706                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15707                            value.templates.extend(lsp_tasks.templates);
15708                        }
15709
15710                        editor.insert_tasks(key, value);
15711                    }
15712                    for (key, value) in lsp_tasks_by_rows {
15713                        editor.insert_tasks(key, value);
15714                    }
15715                })
15716                .ok();
15717        })
15718    }
15719    fn fetch_runnable_ranges(
15720        snapshot: &DisplaySnapshot,
15721        range: Range<Anchor>,
15722    ) -> Vec<language::RunnableRange> {
15723        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15724    }
15725
15726    fn runnable_rows(
15727        project: Entity<Project>,
15728        snapshot: DisplaySnapshot,
15729        prefer_lsp: bool,
15730        runnable_ranges: Vec<RunnableRange>,
15731        cx: AsyncWindowContext,
15732    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15733        cx.spawn(async move |cx| {
15734            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15735            for mut runnable in runnable_ranges {
15736                let Some(tasks) = cx
15737                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15738                    .ok()
15739                else {
15740                    continue;
15741                };
15742                let mut tasks = tasks.await;
15743
15744                if prefer_lsp {
15745                    tasks.retain(|(task_kind, _)| {
15746                        !matches!(task_kind, TaskSourceKind::Language { .. })
15747                    });
15748                }
15749                if tasks.is_empty() {
15750                    continue;
15751                }
15752
15753                let point = runnable
15754                    .run_range
15755                    .start
15756                    .to_point(&snapshot.buffer_snapshot());
15757                let Some(row) = snapshot
15758                    .buffer_snapshot()
15759                    .buffer_line_for_row(MultiBufferRow(point.row))
15760                    .map(|(_, range)| range.start.row)
15761                else {
15762                    continue;
15763                };
15764
15765                let context_range =
15766                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15767                runnable_rows.push((
15768                    (runnable.buffer_id, row),
15769                    RunnableTasks {
15770                        templates: tasks,
15771                        offset: snapshot
15772                            .buffer_snapshot()
15773                            .anchor_before(runnable.run_range.start),
15774                        context_range,
15775                        column: point.column,
15776                        extra_variables: runnable.extra_captures,
15777                    },
15778                ));
15779            }
15780            runnable_rows
15781        })
15782    }
15783
15784    fn templates_with_tags(
15785        project: &Entity<Project>,
15786        runnable: &mut Runnable,
15787        cx: &mut App,
15788    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15789        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15790            let (worktree_id, file) = project
15791                .buffer_for_id(runnable.buffer, cx)
15792                .and_then(|buffer| buffer.read(cx).file())
15793                .map(|file| (file.worktree_id(cx), file.clone()))
15794                .unzip();
15795
15796            (
15797                project.task_store().read(cx).task_inventory().cloned(),
15798                worktree_id,
15799                file,
15800            )
15801        });
15802
15803        let tags = mem::take(&mut runnable.tags);
15804        let language = runnable.language.clone();
15805        cx.spawn(async move |cx| {
15806            let mut templates_with_tags = Vec::new();
15807            if let Some(inventory) = inventory {
15808                for RunnableTag(tag) in tags {
15809                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15810                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15811                    }) else {
15812                        return templates_with_tags;
15813                    };
15814                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15815                        move |(_, template)| {
15816                            template.tags.iter().any(|source_tag| source_tag == &tag)
15817                        },
15818                    ));
15819                }
15820            }
15821            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15822
15823            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15824                // Strongest source wins; if we have worktree tag binding, prefer that to
15825                // global and language bindings;
15826                // if we have a global binding, prefer that to language binding.
15827                let first_mismatch = templates_with_tags
15828                    .iter()
15829                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15830                if let Some(index) = first_mismatch {
15831                    templates_with_tags.truncate(index);
15832                }
15833            }
15834
15835            templates_with_tags
15836        })
15837    }
15838
15839    pub fn move_to_enclosing_bracket(
15840        &mut self,
15841        _: &MoveToEnclosingBracket,
15842        window: &mut Window,
15843        cx: &mut Context<Self>,
15844    ) {
15845        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15846        self.change_selections(Default::default(), window, cx, |s| {
15847            s.move_offsets_with(|snapshot, selection| {
15848                let Some(enclosing_bracket_ranges) =
15849                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15850                else {
15851                    return;
15852                };
15853
15854                let mut best_length = usize::MAX;
15855                let mut best_inside = false;
15856                let mut best_in_bracket_range = false;
15857                let mut best_destination = None;
15858                for (open, close) in enclosing_bracket_ranges {
15859                    let close = close.to_inclusive();
15860                    let length = close.end() - open.start;
15861                    let inside = selection.start >= open.end && selection.end <= *close.start();
15862                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15863                        || close.contains(&selection.head());
15864
15865                    // If best is next to a bracket and current isn't, skip
15866                    if !in_bracket_range && best_in_bracket_range {
15867                        continue;
15868                    }
15869
15870                    // Prefer smaller lengths unless best is inside and current isn't
15871                    if length > best_length && (best_inside || !inside) {
15872                        continue;
15873                    }
15874
15875                    best_length = length;
15876                    best_inside = inside;
15877                    best_in_bracket_range = in_bracket_range;
15878                    best_destination = Some(
15879                        if close.contains(&selection.start) && close.contains(&selection.end) {
15880                            if inside { open.end } else { open.start }
15881                        } else if inside {
15882                            *close.start()
15883                        } else {
15884                            *close.end()
15885                        },
15886                    );
15887                }
15888
15889                if let Some(destination) = best_destination {
15890                    selection.collapse_to(destination, SelectionGoal::None);
15891                }
15892            })
15893        });
15894    }
15895
15896    pub fn undo_selection(
15897        &mut self,
15898        _: &UndoSelection,
15899        window: &mut Window,
15900        cx: &mut Context<Self>,
15901    ) {
15902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15903        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15904            self.selection_history.mode = SelectionHistoryMode::Undoing;
15905            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15906                this.end_selection(window, cx);
15907                this.change_selections(
15908                    SelectionEffects::scroll(Autoscroll::newest()),
15909                    window,
15910                    cx,
15911                    |s| s.select_anchors(entry.selections.to_vec()),
15912                );
15913            });
15914            self.selection_history.mode = SelectionHistoryMode::Normal;
15915
15916            self.select_next_state = entry.select_next_state;
15917            self.select_prev_state = entry.select_prev_state;
15918            self.add_selections_state = entry.add_selections_state;
15919        }
15920    }
15921
15922    pub fn redo_selection(
15923        &mut self,
15924        _: &RedoSelection,
15925        window: &mut Window,
15926        cx: &mut Context<Self>,
15927    ) {
15928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15929        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15930            self.selection_history.mode = SelectionHistoryMode::Redoing;
15931            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15932                this.end_selection(window, cx);
15933                this.change_selections(
15934                    SelectionEffects::scroll(Autoscroll::newest()),
15935                    window,
15936                    cx,
15937                    |s| s.select_anchors(entry.selections.to_vec()),
15938                );
15939            });
15940            self.selection_history.mode = SelectionHistoryMode::Normal;
15941
15942            self.select_next_state = entry.select_next_state;
15943            self.select_prev_state = entry.select_prev_state;
15944            self.add_selections_state = entry.add_selections_state;
15945        }
15946    }
15947
15948    pub fn expand_excerpts(
15949        &mut self,
15950        action: &ExpandExcerpts,
15951        _: &mut Window,
15952        cx: &mut Context<Self>,
15953    ) {
15954        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15955    }
15956
15957    pub fn expand_excerpts_down(
15958        &mut self,
15959        action: &ExpandExcerptsDown,
15960        _: &mut Window,
15961        cx: &mut Context<Self>,
15962    ) {
15963        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15964    }
15965
15966    pub fn expand_excerpts_up(
15967        &mut self,
15968        action: &ExpandExcerptsUp,
15969        _: &mut Window,
15970        cx: &mut Context<Self>,
15971    ) {
15972        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15973    }
15974
15975    pub fn expand_excerpts_for_direction(
15976        &mut self,
15977        lines: u32,
15978        direction: ExpandExcerptDirection,
15979
15980        cx: &mut Context<Self>,
15981    ) {
15982        let selections = self.selections.disjoint_anchors_arc();
15983
15984        let lines = if lines == 0 {
15985            EditorSettings::get_global(cx).expand_excerpt_lines
15986        } else {
15987            lines
15988        };
15989
15990        self.buffer.update(cx, |buffer, cx| {
15991            let snapshot = buffer.snapshot(cx);
15992            let mut excerpt_ids = selections
15993                .iter()
15994                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15995                .collect::<Vec<_>>();
15996            excerpt_ids.sort();
15997            excerpt_ids.dedup();
15998            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15999        })
16000    }
16001
16002    pub fn expand_excerpt(
16003        &mut self,
16004        excerpt: ExcerptId,
16005        direction: ExpandExcerptDirection,
16006        window: &mut Window,
16007        cx: &mut Context<Self>,
16008    ) {
16009        let current_scroll_position = self.scroll_position(cx);
16010        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16011        let mut should_scroll_up = false;
16012
16013        if direction == ExpandExcerptDirection::Down {
16014            let multi_buffer = self.buffer.read(cx);
16015            let snapshot = multi_buffer.snapshot(cx);
16016            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16017                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16018                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16019            {
16020                let buffer_snapshot = buffer.read(cx).snapshot();
16021                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16022                let last_row = buffer_snapshot.max_point().row;
16023                let lines_below = last_row.saturating_sub(excerpt_end_row);
16024                should_scroll_up = lines_below >= lines_to_expand;
16025            }
16026        }
16027
16028        self.buffer.update(cx, |buffer, cx| {
16029            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16030        });
16031
16032        if should_scroll_up {
16033            let new_scroll_position =
16034                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
16035            self.set_scroll_position(new_scroll_position, window, cx);
16036        }
16037    }
16038
16039    pub fn go_to_singleton_buffer_point(
16040        &mut self,
16041        point: Point,
16042        window: &mut Window,
16043        cx: &mut Context<Self>,
16044    ) {
16045        self.go_to_singleton_buffer_range(point..point, window, cx);
16046    }
16047
16048    pub fn go_to_singleton_buffer_range(
16049        &mut self,
16050        range: Range<Point>,
16051        window: &mut Window,
16052        cx: &mut Context<Self>,
16053    ) {
16054        let multibuffer = self.buffer().read(cx);
16055        let Some(buffer) = multibuffer.as_singleton() else {
16056            return;
16057        };
16058        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16059            return;
16060        };
16061        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16062            return;
16063        };
16064        self.change_selections(
16065            SelectionEffects::default().nav_history(true),
16066            window,
16067            cx,
16068            |s| s.select_anchor_ranges([start..end]),
16069        );
16070    }
16071
16072    pub fn go_to_diagnostic(
16073        &mut self,
16074        action: &GoToDiagnostic,
16075        window: &mut Window,
16076        cx: &mut Context<Self>,
16077    ) {
16078        if !self.diagnostics_enabled() {
16079            return;
16080        }
16081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16082        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16083    }
16084
16085    pub fn go_to_prev_diagnostic(
16086        &mut self,
16087        action: &GoToPreviousDiagnostic,
16088        window: &mut Window,
16089        cx: &mut Context<Self>,
16090    ) {
16091        if !self.diagnostics_enabled() {
16092            return;
16093        }
16094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16095        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16096    }
16097
16098    pub fn go_to_diagnostic_impl(
16099        &mut self,
16100        direction: Direction,
16101        severity: GoToDiagnosticSeverityFilter,
16102        window: &mut Window,
16103        cx: &mut Context<Self>,
16104    ) {
16105        let buffer = self.buffer.read(cx).snapshot(cx);
16106        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16107
16108        let mut active_group_id = None;
16109        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16110            && active_group.active_range.start.to_offset(&buffer) == selection.start
16111        {
16112            active_group_id = Some(active_group.group_id);
16113        }
16114
16115        fn filtered<'a>(
16116            snapshot: EditorSnapshot,
16117            severity: GoToDiagnosticSeverityFilter,
16118            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16119        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16120            diagnostics
16121                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16122                .filter(|entry| entry.range.start != entry.range.end)
16123                .filter(|entry| !entry.diagnostic.is_unnecessary)
16124                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16125        }
16126
16127        let snapshot = self.snapshot(window, cx);
16128        let before = filtered(
16129            snapshot.clone(),
16130            severity,
16131            buffer
16132                .diagnostics_in_range(0..selection.start)
16133                .filter(|entry| entry.range.start <= selection.start),
16134        );
16135        let after = filtered(
16136            snapshot,
16137            severity,
16138            buffer
16139                .diagnostics_in_range(selection.start..buffer.len())
16140                .filter(|entry| entry.range.start >= selection.start),
16141        );
16142
16143        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16144        if direction == Direction::Prev {
16145            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16146            {
16147                for diagnostic in prev_diagnostics.into_iter().rev() {
16148                    if diagnostic.range.start != selection.start
16149                        || active_group_id
16150                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16151                    {
16152                        found = Some(diagnostic);
16153                        break 'outer;
16154                    }
16155                }
16156            }
16157        } else {
16158            for diagnostic in after.chain(before) {
16159                if diagnostic.range.start != selection.start
16160                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16161                {
16162                    found = Some(diagnostic);
16163                    break;
16164                }
16165            }
16166        }
16167        let Some(next_diagnostic) = found else {
16168            return;
16169        };
16170
16171        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16172        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16173            return;
16174        };
16175        self.change_selections(Default::default(), window, cx, |s| {
16176            s.select_ranges(vec![
16177                next_diagnostic.range.start..next_diagnostic.range.start,
16178            ])
16179        });
16180        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16181        self.refresh_edit_prediction(false, true, window, cx);
16182    }
16183
16184    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16186        let snapshot = self.snapshot(window, cx);
16187        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16188        self.go_to_hunk_before_or_after_position(
16189            &snapshot,
16190            selection.head(),
16191            Direction::Next,
16192            window,
16193            cx,
16194        );
16195    }
16196
16197    pub fn go_to_hunk_before_or_after_position(
16198        &mut self,
16199        snapshot: &EditorSnapshot,
16200        position: Point,
16201        direction: Direction,
16202        window: &mut Window,
16203        cx: &mut Context<Editor>,
16204    ) {
16205        let row = if direction == Direction::Next {
16206            self.hunk_after_position(snapshot, position)
16207                .map(|hunk| hunk.row_range.start)
16208        } else {
16209            self.hunk_before_position(snapshot, position)
16210        };
16211
16212        if let Some(row) = row {
16213            let destination = Point::new(row.0, 0);
16214            let autoscroll = Autoscroll::center();
16215
16216            self.unfold_ranges(&[destination..destination], false, false, cx);
16217            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16218                s.select_ranges([destination..destination]);
16219            });
16220        }
16221    }
16222
16223    fn hunk_after_position(
16224        &mut self,
16225        snapshot: &EditorSnapshot,
16226        position: Point,
16227    ) -> Option<MultiBufferDiffHunk> {
16228        snapshot
16229            .buffer_snapshot()
16230            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16231            .find(|hunk| hunk.row_range.start.0 > position.row)
16232            .or_else(|| {
16233                snapshot
16234                    .buffer_snapshot()
16235                    .diff_hunks_in_range(Point::zero()..position)
16236                    .find(|hunk| hunk.row_range.end.0 < position.row)
16237            })
16238    }
16239
16240    fn go_to_prev_hunk(
16241        &mut self,
16242        _: &GoToPreviousHunk,
16243        window: &mut Window,
16244        cx: &mut Context<Self>,
16245    ) {
16246        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16247        let snapshot = self.snapshot(window, cx);
16248        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16249        self.go_to_hunk_before_or_after_position(
16250            &snapshot,
16251            selection.head(),
16252            Direction::Prev,
16253            window,
16254            cx,
16255        );
16256    }
16257
16258    fn hunk_before_position(
16259        &mut self,
16260        snapshot: &EditorSnapshot,
16261        position: Point,
16262    ) -> Option<MultiBufferRow> {
16263        snapshot
16264            .buffer_snapshot()
16265            .diff_hunk_before(position)
16266            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16267    }
16268
16269    fn go_to_next_change(
16270        &mut self,
16271        _: &GoToNextChange,
16272        window: &mut Window,
16273        cx: &mut Context<Self>,
16274    ) {
16275        if let Some(selections) = self
16276            .change_list
16277            .next_change(1, Direction::Next)
16278            .map(|s| s.to_vec())
16279        {
16280            self.change_selections(Default::default(), window, cx, |s| {
16281                let map = s.display_map();
16282                s.select_display_ranges(selections.iter().map(|a| {
16283                    let point = a.to_display_point(&map);
16284                    point..point
16285                }))
16286            })
16287        }
16288    }
16289
16290    fn go_to_previous_change(
16291        &mut self,
16292        _: &GoToPreviousChange,
16293        window: &mut Window,
16294        cx: &mut Context<Self>,
16295    ) {
16296        if let Some(selections) = self
16297            .change_list
16298            .next_change(1, Direction::Prev)
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    pub fn go_to_next_document_highlight(
16312        &mut self,
16313        _: &GoToNextDocumentHighlight,
16314        window: &mut Window,
16315        cx: &mut Context<Self>,
16316    ) {
16317        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16318    }
16319
16320    pub fn go_to_prev_document_highlight(
16321        &mut self,
16322        _: &GoToPreviousDocumentHighlight,
16323        window: &mut Window,
16324        cx: &mut Context<Self>,
16325    ) {
16326        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16327    }
16328
16329    pub fn go_to_document_highlight_before_or_after_position(
16330        &mut self,
16331        direction: Direction,
16332        window: &mut Window,
16333        cx: &mut Context<Editor>,
16334    ) {
16335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16336        let snapshot = self.snapshot(window, cx);
16337        let buffer = &snapshot.buffer_snapshot();
16338        let position = self
16339            .selections
16340            .newest::<Point>(&snapshot.display_snapshot)
16341            .head();
16342        let anchor_position = buffer.anchor_after(position);
16343
16344        // Get all document highlights (both read and write)
16345        let mut all_highlights = Vec::new();
16346
16347        if let Some((_, read_highlights)) = self
16348            .background_highlights
16349            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16350        {
16351            all_highlights.extend(read_highlights.iter());
16352        }
16353
16354        if let Some((_, write_highlights)) = self
16355            .background_highlights
16356            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16357        {
16358            all_highlights.extend(write_highlights.iter());
16359        }
16360
16361        if all_highlights.is_empty() {
16362            return;
16363        }
16364
16365        // Sort highlights by position
16366        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16367
16368        let target_highlight = match direction {
16369            Direction::Next => {
16370                // Find the first highlight after the current position
16371                all_highlights
16372                    .iter()
16373                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16374            }
16375            Direction::Prev => {
16376                // Find the last highlight before the current position
16377                all_highlights
16378                    .iter()
16379                    .rev()
16380                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16381            }
16382        };
16383
16384        if let Some(highlight) = target_highlight {
16385            let destination = highlight.start.to_point(buffer);
16386            let autoscroll = Autoscroll::center();
16387
16388            self.unfold_ranges(&[destination..destination], false, false, cx);
16389            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16390                s.select_ranges([destination..destination]);
16391            });
16392        }
16393    }
16394
16395    fn go_to_line<T: 'static>(
16396        &mut self,
16397        position: Anchor,
16398        highlight_color: Option<Hsla>,
16399        window: &mut Window,
16400        cx: &mut Context<Self>,
16401    ) {
16402        let snapshot = self.snapshot(window, cx).display_snapshot;
16403        let position = position.to_point(&snapshot.buffer_snapshot());
16404        let start = snapshot
16405            .buffer_snapshot()
16406            .clip_point(Point::new(position.row, 0), Bias::Left);
16407        let end = start + Point::new(1, 0);
16408        let start = snapshot.buffer_snapshot().anchor_before(start);
16409        let end = snapshot.buffer_snapshot().anchor_before(end);
16410
16411        self.highlight_rows::<T>(
16412            start..end,
16413            highlight_color
16414                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16415            Default::default(),
16416            cx,
16417        );
16418
16419        if self.buffer.read(cx).is_singleton() {
16420            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16421        }
16422    }
16423
16424    pub fn go_to_definition(
16425        &mut self,
16426        _: &GoToDefinition,
16427        window: &mut Window,
16428        cx: &mut Context<Self>,
16429    ) -> Task<Result<Navigated>> {
16430        let definition =
16431            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16432        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16433        cx.spawn_in(window, async move |editor, cx| {
16434            if definition.await? == Navigated::Yes {
16435                return Ok(Navigated::Yes);
16436            }
16437            match fallback_strategy {
16438                GoToDefinitionFallback::None => Ok(Navigated::No),
16439                GoToDefinitionFallback::FindAllReferences => {
16440                    match editor.update_in(cx, |editor, window, cx| {
16441                        editor.find_all_references(&FindAllReferences, window, cx)
16442                    })? {
16443                        Some(references) => references.await,
16444                        None => Ok(Navigated::No),
16445                    }
16446                }
16447            }
16448        })
16449    }
16450
16451    pub fn go_to_declaration(
16452        &mut self,
16453        _: &GoToDeclaration,
16454        window: &mut Window,
16455        cx: &mut Context<Self>,
16456    ) -> Task<Result<Navigated>> {
16457        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16458    }
16459
16460    pub fn go_to_declaration_split(
16461        &mut self,
16462        _: &GoToDeclaration,
16463        window: &mut Window,
16464        cx: &mut Context<Self>,
16465    ) -> Task<Result<Navigated>> {
16466        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16467    }
16468
16469    pub fn go_to_implementation(
16470        &mut self,
16471        _: &GoToImplementation,
16472        window: &mut Window,
16473        cx: &mut Context<Self>,
16474    ) -> Task<Result<Navigated>> {
16475        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16476    }
16477
16478    pub fn go_to_implementation_split(
16479        &mut self,
16480        _: &GoToImplementationSplit,
16481        window: &mut Window,
16482        cx: &mut Context<Self>,
16483    ) -> Task<Result<Navigated>> {
16484        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16485    }
16486
16487    pub fn go_to_type_definition(
16488        &mut self,
16489        _: &GoToTypeDefinition,
16490        window: &mut Window,
16491        cx: &mut Context<Self>,
16492    ) -> Task<Result<Navigated>> {
16493        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16494    }
16495
16496    pub fn go_to_definition_split(
16497        &mut self,
16498        _: &GoToDefinitionSplit,
16499        window: &mut Window,
16500        cx: &mut Context<Self>,
16501    ) -> Task<Result<Navigated>> {
16502        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16503    }
16504
16505    pub fn go_to_type_definition_split(
16506        &mut self,
16507        _: &GoToTypeDefinitionSplit,
16508        window: &mut Window,
16509        cx: &mut Context<Self>,
16510    ) -> Task<Result<Navigated>> {
16511        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16512    }
16513
16514    fn go_to_definition_of_kind(
16515        &mut self,
16516        kind: GotoDefinitionKind,
16517        split: bool,
16518        window: &mut Window,
16519        cx: &mut Context<Self>,
16520    ) -> Task<Result<Navigated>> {
16521        let Some(provider) = self.semantics_provider.clone() else {
16522            return Task::ready(Ok(Navigated::No));
16523        };
16524        let head = self
16525            .selections
16526            .newest::<usize>(&self.display_snapshot(cx))
16527            .head();
16528        let buffer = self.buffer.read(cx);
16529        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16530            return Task::ready(Ok(Navigated::No));
16531        };
16532        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16533            return Task::ready(Ok(Navigated::No));
16534        };
16535
16536        cx.spawn_in(window, async move |editor, cx| {
16537            let Some(definitions) = definitions.await? else {
16538                return Ok(Navigated::No);
16539            };
16540            let navigated = editor
16541                .update_in(cx, |editor, window, cx| {
16542                    editor.navigate_to_hover_links(
16543                        Some(kind),
16544                        definitions
16545                            .into_iter()
16546                            .filter(|location| {
16547                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16548                            })
16549                            .map(HoverLink::Text)
16550                            .collect::<Vec<_>>(),
16551                        split,
16552                        window,
16553                        cx,
16554                    )
16555                })?
16556                .await?;
16557            anyhow::Ok(navigated)
16558        })
16559    }
16560
16561    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16562        let selection = self.selections.newest_anchor();
16563        let head = selection.head();
16564        let tail = selection.tail();
16565
16566        let Some((buffer, start_position)) =
16567            self.buffer.read(cx).text_anchor_for_position(head, cx)
16568        else {
16569            return;
16570        };
16571
16572        let end_position = if head != tail {
16573            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16574                return;
16575            };
16576            Some(pos)
16577        } else {
16578            None
16579        };
16580
16581        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16582            let url = if let Some(end_pos) = end_position {
16583                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16584            } else {
16585                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16586            };
16587
16588            if let Some(url) = url {
16589                cx.update(|window, cx| {
16590                    if parse_zed_link(&url, cx).is_some() {
16591                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16592                    } else {
16593                        cx.open_url(&url);
16594                    }
16595                })?;
16596            }
16597
16598            anyhow::Ok(())
16599        });
16600
16601        url_finder.detach();
16602    }
16603
16604    pub fn open_selected_filename(
16605        &mut self,
16606        _: &OpenSelectedFilename,
16607        window: &mut Window,
16608        cx: &mut Context<Self>,
16609    ) {
16610        let Some(workspace) = self.workspace() else {
16611            return;
16612        };
16613
16614        let position = self.selections.newest_anchor().head();
16615
16616        let Some((buffer, buffer_position)) =
16617            self.buffer.read(cx).text_anchor_for_position(position, cx)
16618        else {
16619            return;
16620        };
16621
16622        let project = self.project.clone();
16623
16624        cx.spawn_in(window, async move |_, cx| {
16625            let result = find_file(&buffer, project, buffer_position, cx).await;
16626
16627            if let Some((_, path)) = result {
16628                workspace
16629                    .update_in(cx, |workspace, window, cx| {
16630                        workspace.open_resolved_path(path, window, cx)
16631                    })?
16632                    .await?;
16633            }
16634            anyhow::Ok(())
16635        })
16636        .detach();
16637    }
16638
16639    pub(crate) fn navigate_to_hover_links(
16640        &mut self,
16641        kind: Option<GotoDefinitionKind>,
16642        definitions: Vec<HoverLink>,
16643        split: bool,
16644        window: &mut Window,
16645        cx: &mut Context<Editor>,
16646    ) -> Task<Result<Navigated>> {
16647        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16648        let mut first_url_or_file = None;
16649        let definitions: Vec<_> = definitions
16650            .into_iter()
16651            .filter_map(|def| match def {
16652                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16653                HoverLink::InlayHint(lsp_location, server_id) => {
16654                    let computation =
16655                        self.compute_target_location(lsp_location, server_id, window, cx);
16656                    Some(cx.background_spawn(computation))
16657                }
16658                HoverLink::Url(url) => {
16659                    first_url_or_file = Some(Either::Left(url));
16660                    None
16661                }
16662                HoverLink::File(path) => {
16663                    first_url_or_file = Some(Either::Right(path));
16664                    None
16665                }
16666            })
16667            .collect();
16668
16669        let workspace = self.workspace();
16670
16671        cx.spawn_in(window, async move |editor, cx| {
16672            let locations: Vec<Location> = future::join_all(definitions)
16673                .await
16674                .into_iter()
16675                .filter_map(|location| location.transpose())
16676                .collect::<Result<_>>()
16677                .context("location tasks")?;
16678            let mut locations = cx.update(|_, cx| {
16679                locations
16680                    .into_iter()
16681                    .map(|location| {
16682                        let buffer = location.buffer.read(cx);
16683                        (location.buffer, location.range.to_point(buffer))
16684                    })
16685                    .into_group_map()
16686            })?;
16687            let mut num_locations = 0;
16688            for ranges in locations.values_mut() {
16689                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16690                ranges.dedup();
16691                num_locations += ranges.len();
16692            }
16693
16694            if num_locations > 1 {
16695                let Some(workspace) = workspace else {
16696                    return Ok(Navigated::No);
16697                };
16698
16699                let tab_kind = match kind {
16700                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16701                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16702                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16703                    Some(GotoDefinitionKind::Type) => "Types",
16704                };
16705                let title = editor
16706                    .update_in(cx, |_, _, cx| {
16707                        let target = locations
16708                            .iter()
16709                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16710                            .map(|(buffer, location)| {
16711                                buffer
16712                                    .read(cx)
16713                                    .text_for_range(location.clone())
16714                                    .collect::<String>()
16715                            })
16716                            .filter(|text| !text.contains('\n'))
16717                            .unique()
16718                            .take(3)
16719                            .join(", ");
16720                        if target.is_empty() {
16721                            tab_kind.to_owned()
16722                        } else {
16723                            format!("{tab_kind} for {target}")
16724                        }
16725                    })
16726                    .context("buffer title")?;
16727
16728                let opened = workspace
16729                    .update_in(cx, |workspace, window, cx| {
16730                        Self::open_locations_in_multibuffer(
16731                            workspace,
16732                            locations,
16733                            title,
16734                            split,
16735                            MultibufferSelectionMode::First,
16736                            window,
16737                            cx,
16738                        )
16739                    })
16740                    .is_ok();
16741
16742                anyhow::Ok(Navigated::from_bool(opened))
16743            } else if num_locations == 0 {
16744                // If there is one url or file, open it directly
16745                match first_url_or_file {
16746                    Some(Either::Left(url)) => {
16747                        cx.update(|_, cx| cx.open_url(&url))?;
16748                        Ok(Navigated::Yes)
16749                    }
16750                    Some(Either::Right(path)) => {
16751                        let Some(workspace) = workspace else {
16752                            return Ok(Navigated::No);
16753                        };
16754
16755                        workspace
16756                            .update_in(cx, |workspace, window, cx| {
16757                                workspace.open_resolved_path(path, window, cx)
16758                            })?
16759                            .await?;
16760                        Ok(Navigated::Yes)
16761                    }
16762                    None => Ok(Navigated::No),
16763                }
16764            } else {
16765                let Some(workspace) = workspace else {
16766                    return Ok(Navigated::No);
16767                };
16768
16769                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16770                let target_range = target_ranges.first().unwrap().clone();
16771
16772                editor.update_in(cx, |editor, window, cx| {
16773                    let range = target_range.to_point(target_buffer.read(cx));
16774                    let range = editor.range_for_match(&range);
16775                    let range = collapse_multiline_range(range);
16776
16777                    if !split
16778                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16779                    {
16780                        editor.go_to_singleton_buffer_range(range, window, cx);
16781                    } else {
16782                        let pane = workspace.read(cx).active_pane().clone();
16783                        window.defer(cx, move |window, cx| {
16784                            let target_editor: Entity<Self> =
16785                                workspace.update(cx, |workspace, cx| {
16786                                    let pane = if split {
16787                                        workspace.adjacent_pane(window, cx)
16788                                    } else {
16789                                        workspace.active_pane().clone()
16790                                    };
16791
16792                                    workspace.open_project_item(
16793                                        pane,
16794                                        target_buffer.clone(),
16795                                        true,
16796                                        true,
16797                                        window,
16798                                        cx,
16799                                    )
16800                                });
16801                            target_editor.update(cx, |target_editor, cx| {
16802                                // When selecting a definition in a different buffer, disable the nav history
16803                                // to avoid creating a history entry at the previous cursor location.
16804                                pane.update(cx, |pane, _| pane.disable_history());
16805                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16806                                pane.update(cx, |pane, _| pane.enable_history());
16807                            });
16808                        });
16809                    }
16810                    Navigated::Yes
16811                })
16812            }
16813        })
16814    }
16815
16816    fn compute_target_location(
16817        &self,
16818        lsp_location: lsp::Location,
16819        server_id: LanguageServerId,
16820        window: &mut Window,
16821        cx: &mut Context<Self>,
16822    ) -> Task<anyhow::Result<Option<Location>>> {
16823        let Some(project) = self.project.clone() else {
16824            return Task::ready(Ok(None));
16825        };
16826
16827        cx.spawn_in(window, async move |editor, cx| {
16828            let location_task = editor.update(cx, |_, cx| {
16829                project.update(cx, |project, cx| {
16830                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16831                })
16832            })?;
16833            let location = Some({
16834                let target_buffer_handle = location_task.await.context("open local buffer")?;
16835                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16836                    let target_start = target_buffer
16837                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16838                    let target_end = target_buffer
16839                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16840                    target_buffer.anchor_after(target_start)
16841                        ..target_buffer.anchor_before(target_end)
16842                })?;
16843                Location {
16844                    buffer: target_buffer_handle,
16845                    range,
16846                }
16847            });
16848            Ok(location)
16849        })
16850    }
16851
16852    pub fn find_all_references(
16853        &mut self,
16854        _: &FindAllReferences,
16855        window: &mut Window,
16856        cx: &mut Context<Self>,
16857    ) -> Option<Task<Result<Navigated>>> {
16858        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16859        let multi_buffer = self.buffer.read(cx);
16860        let head = selection.head();
16861
16862        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16863        let head_anchor = multi_buffer_snapshot.anchor_at(
16864            head,
16865            if head < selection.tail() {
16866                Bias::Right
16867            } else {
16868                Bias::Left
16869            },
16870        );
16871
16872        match self
16873            .find_all_references_task_sources
16874            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16875        {
16876            Ok(_) => {
16877                log::info!(
16878                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16879                );
16880                return None;
16881            }
16882            Err(i) => {
16883                self.find_all_references_task_sources.insert(i, head_anchor);
16884            }
16885        }
16886
16887        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16888        let workspace = self.workspace()?;
16889        let project = workspace.read(cx).project().clone();
16890        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16891        Some(cx.spawn_in(window, async move |editor, cx| {
16892            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16893                if let Ok(i) = editor
16894                    .find_all_references_task_sources
16895                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16896                {
16897                    editor.find_all_references_task_sources.remove(i);
16898                }
16899            });
16900
16901            let Some(locations) = references.await? else {
16902                return anyhow::Ok(Navigated::No);
16903            };
16904            let mut locations = cx.update(|_, cx| {
16905                locations
16906                    .into_iter()
16907                    .map(|location| {
16908                        let buffer = location.buffer.read(cx);
16909                        (location.buffer, location.range.to_point(buffer))
16910                    })
16911                    .into_group_map()
16912            })?;
16913            if locations.is_empty() {
16914                return anyhow::Ok(Navigated::No);
16915            }
16916            for ranges in locations.values_mut() {
16917                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16918                ranges.dedup();
16919            }
16920
16921            workspace.update_in(cx, |workspace, window, cx| {
16922                let target = locations
16923                    .iter()
16924                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16925                    .map(|(buffer, location)| {
16926                        buffer
16927                            .read(cx)
16928                            .text_for_range(location.clone())
16929                            .collect::<String>()
16930                    })
16931                    .filter(|text| !text.contains('\n'))
16932                    .unique()
16933                    .take(3)
16934                    .join(", ");
16935                let title = if target.is_empty() {
16936                    "References".to_owned()
16937                } else {
16938                    format!("References to {target}")
16939                };
16940                Self::open_locations_in_multibuffer(
16941                    workspace,
16942                    locations,
16943                    title,
16944                    false,
16945                    MultibufferSelectionMode::First,
16946                    window,
16947                    cx,
16948                );
16949                Navigated::Yes
16950            })
16951        }))
16952    }
16953
16954    /// Opens a multibuffer with the given project locations in it
16955    pub fn open_locations_in_multibuffer(
16956        workspace: &mut Workspace,
16957        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16958        title: String,
16959        split: bool,
16960        multibuffer_selection_mode: MultibufferSelectionMode,
16961        window: &mut Window,
16962        cx: &mut Context<Workspace>,
16963    ) {
16964        if locations.is_empty() {
16965            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16966            return;
16967        }
16968
16969        let capability = workspace.project().read(cx).capability();
16970        let mut ranges = <Vec<Range<Anchor>>>::new();
16971
16972        // a key to find existing multibuffer editors with the same set of locations
16973        // to prevent us from opening more and more multibuffer tabs for searches and the like
16974        let mut key = (title.clone(), vec![]);
16975        let excerpt_buffer = cx.new(|cx| {
16976            let key = &mut key.1;
16977            let mut multibuffer = MultiBuffer::new(capability);
16978            for (buffer, mut ranges_for_buffer) in locations {
16979                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16980                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16981                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16982                    PathKey::for_buffer(&buffer, cx),
16983                    buffer.clone(),
16984                    ranges_for_buffer,
16985                    multibuffer_context_lines(cx),
16986                    cx,
16987                );
16988                ranges.extend(new_ranges)
16989            }
16990
16991            multibuffer.with_title(title)
16992        });
16993        let existing = workspace.active_pane().update(cx, |pane, cx| {
16994            pane.items()
16995                .filter_map(|item| item.downcast::<Editor>())
16996                .find(|editor| {
16997                    editor
16998                        .read(cx)
16999                        .lookup_key
17000                        .as_ref()
17001                        .and_then(|it| {
17002                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17003                        })
17004                        .is_some_and(|it| *it == key)
17005                })
17006        });
17007        let editor = existing.unwrap_or_else(|| {
17008            cx.new(|cx| {
17009                let mut editor = Editor::for_multibuffer(
17010                    excerpt_buffer,
17011                    Some(workspace.project().clone()),
17012                    window,
17013                    cx,
17014                );
17015                editor.lookup_key = Some(Box::new(key));
17016                editor
17017            })
17018        });
17019        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17020            MultibufferSelectionMode::First => {
17021                if let Some(first_range) = ranges.first() {
17022                    editor.change_selections(
17023                        SelectionEffects::no_scroll(),
17024                        window,
17025                        cx,
17026                        |selections| {
17027                            selections.clear_disjoint();
17028                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17029                        },
17030                    );
17031                }
17032                editor.highlight_background::<Self>(
17033                    &ranges,
17034                    |theme| theme.colors().editor_highlighted_line_background,
17035                    cx,
17036                );
17037            }
17038            MultibufferSelectionMode::All => {
17039                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17040                    selections.clear_disjoint();
17041                    selections.select_anchor_ranges(ranges);
17042                });
17043            }
17044        });
17045
17046        let item = Box::new(editor);
17047        let item_id = item.item_id();
17048
17049        if split {
17050            let pane = workspace.adjacent_pane(window, cx);
17051            workspace.add_item(pane, item, None, true, true, window, cx);
17052        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17053            let (preview_item_id, preview_item_idx) =
17054                workspace.active_pane().read_with(cx, |pane, _| {
17055                    (pane.preview_item_id(), pane.preview_item_idx())
17056                });
17057
17058            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17059
17060            if let Some(preview_item_id) = preview_item_id {
17061                workspace.active_pane().update(cx, |pane, cx| {
17062                    pane.remove_item(preview_item_id, false, false, window, cx);
17063                });
17064            }
17065        } else {
17066            workspace.add_item_to_active_pane(item, None, true, window, cx);
17067        }
17068        workspace.active_pane().update(cx, |pane, cx| {
17069            pane.set_preview_item_id(Some(item_id), cx);
17070        });
17071    }
17072
17073    pub fn rename(
17074        &mut self,
17075        _: &Rename,
17076        window: &mut Window,
17077        cx: &mut Context<Self>,
17078    ) -> Option<Task<Result<()>>> {
17079        use language::ToOffset as _;
17080
17081        let provider = self.semantics_provider.clone()?;
17082        let selection = self.selections.newest_anchor().clone();
17083        let (cursor_buffer, cursor_buffer_position) = self
17084            .buffer
17085            .read(cx)
17086            .text_anchor_for_position(selection.head(), cx)?;
17087        let (tail_buffer, cursor_buffer_position_end) = self
17088            .buffer
17089            .read(cx)
17090            .text_anchor_for_position(selection.tail(), cx)?;
17091        if tail_buffer != cursor_buffer {
17092            return None;
17093        }
17094
17095        let snapshot = cursor_buffer.read(cx).snapshot();
17096        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17097        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17098        let prepare_rename = provider
17099            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17100            .unwrap_or_else(|| Task::ready(Ok(None)));
17101        drop(snapshot);
17102
17103        Some(cx.spawn_in(window, async move |this, cx| {
17104            let rename_range = if let Some(range) = prepare_rename.await? {
17105                Some(range)
17106            } else {
17107                this.update(cx, |this, cx| {
17108                    let buffer = this.buffer.read(cx).snapshot(cx);
17109                    let mut buffer_highlights = this
17110                        .document_highlights_for_position(selection.head(), &buffer)
17111                        .filter(|highlight| {
17112                            highlight.start.excerpt_id == selection.head().excerpt_id
17113                                && highlight.end.excerpt_id == selection.head().excerpt_id
17114                        });
17115                    buffer_highlights
17116                        .next()
17117                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17118                })?
17119            };
17120            if let Some(rename_range) = rename_range {
17121                this.update_in(cx, |this, window, cx| {
17122                    let snapshot = cursor_buffer.read(cx).snapshot();
17123                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17124                    let cursor_offset_in_rename_range =
17125                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17126                    let cursor_offset_in_rename_range_end =
17127                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17128
17129                    this.take_rename(false, window, cx);
17130                    let buffer = this.buffer.read(cx).read(cx);
17131                    let cursor_offset = selection.head().to_offset(&buffer);
17132                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17133                    let rename_end = rename_start + rename_buffer_range.len();
17134                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17135                    let mut old_highlight_id = None;
17136                    let old_name: Arc<str> = buffer
17137                        .chunks(rename_start..rename_end, true)
17138                        .map(|chunk| {
17139                            if old_highlight_id.is_none() {
17140                                old_highlight_id = chunk.syntax_highlight_id;
17141                            }
17142                            chunk.text
17143                        })
17144                        .collect::<String>()
17145                        .into();
17146
17147                    drop(buffer);
17148
17149                    // Position the selection in the rename editor so that it matches the current selection.
17150                    this.show_local_selections = false;
17151                    let rename_editor = cx.new(|cx| {
17152                        let mut editor = Editor::single_line(window, cx);
17153                        editor.buffer.update(cx, |buffer, cx| {
17154                            buffer.edit([(0..0, old_name.clone())], None, cx)
17155                        });
17156                        let rename_selection_range = match cursor_offset_in_rename_range
17157                            .cmp(&cursor_offset_in_rename_range_end)
17158                        {
17159                            Ordering::Equal => {
17160                                editor.select_all(&SelectAll, window, cx);
17161                                return editor;
17162                            }
17163                            Ordering::Less => {
17164                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17165                            }
17166                            Ordering::Greater => {
17167                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17168                            }
17169                        };
17170                        if rename_selection_range.end > old_name.len() {
17171                            editor.select_all(&SelectAll, window, cx);
17172                        } else {
17173                            editor.change_selections(Default::default(), window, cx, |s| {
17174                                s.select_ranges([rename_selection_range]);
17175                            });
17176                        }
17177                        editor
17178                    });
17179                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17180                        if e == &EditorEvent::Focused {
17181                            cx.emit(EditorEvent::FocusedIn)
17182                        }
17183                    })
17184                    .detach();
17185
17186                    let write_highlights =
17187                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17188                    let read_highlights =
17189                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17190                    let ranges = write_highlights
17191                        .iter()
17192                        .flat_map(|(_, ranges)| ranges.iter())
17193                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17194                        .cloned()
17195                        .collect();
17196
17197                    this.highlight_text::<Rename>(
17198                        ranges,
17199                        HighlightStyle {
17200                            fade_out: Some(0.6),
17201                            ..Default::default()
17202                        },
17203                        cx,
17204                    );
17205                    let rename_focus_handle = rename_editor.focus_handle(cx);
17206                    window.focus(&rename_focus_handle);
17207                    let block_id = this.insert_blocks(
17208                        [BlockProperties {
17209                            style: BlockStyle::Flex,
17210                            placement: BlockPlacement::Below(range.start),
17211                            height: Some(1),
17212                            render: Arc::new({
17213                                let rename_editor = rename_editor.clone();
17214                                move |cx: &mut BlockContext| {
17215                                    let mut text_style = cx.editor_style.text.clone();
17216                                    if let Some(highlight_style) = old_highlight_id
17217                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17218                                    {
17219                                        text_style = text_style.highlight(highlight_style);
17220                                    }
17221                                    div()
17222                                        .block_mouse_except_scroll()
17223                                        .pl(cx.anchor_x)
17224                                        .child(EditorElement::new(
17225                                            &rename_editor,
17226                                            EditorStyle {
17227                                                background: cx.theme().system().transparent,
17228                                                local_player: cx.editor_style.local_player,
17229                                                text: text_style,
17230                                                scrollbar_width: cx.editor_style.scrollbar_width,
17231                                                syntax: cx.editor_style.syntax.clone(),
17232                                                status: cx.editor_style.status.clone(),
17233                                                inlay_hints_style: HighlightStyle {
17234                                                    font_weight: Some(FontWeight::BOLD),
17235                                                    ..make_inlay_hints_style(cx.app)
17236                                                },
17237                                                edit_prediction_styles: make_suggestion_styles(
17238                                                    cx.app,
17239                                                ),
17240                                                ..EditorStyle::default()
17241                                            },
17242                                        ))
17243                                        .into_any_element()
17244                                }
17245                            }),
17246                            priority: 0,
17247                        }],
17248                        Some(Autoscroll::fit()),
17249                        cx,
17250                    )[0];
17251                    this.pending_rename = Some(RenameState {
17252                        range,
17253                        old_name,
17254                        editor: rename_editor,
17255                        block_id,
17256                    });
17257                })?;
17258            }
17259
17260            Ok(())
17261        }))
17262    }
17263
17264    pub fn confirm_rename(
17265        &mut self,
17266        _: &ConfirmRename,
17267        window: &mut Window,
17268        cx: &mut Context<Self>,
17269    ) -> Option<Task<Result<()>>> {
17270        let rename = self.take_rename(false, window, cx)?;
17271        let workspace = self.workspace()?.downgrade();
17272        let (buffer, start) = self
17273            .buffer
17274            .read(cx)
17275            .text_anchor_for_position(rename.range.start, cx)?;
17276        let (end_buffer, _) = self
17277            .buffer
17278            .read(cx)
17279            .text_anchor_for_position(rename.range.end, cx)?;
17280        if buffer != end_buffer {
17281            return None;
17282        }
17283
17284        let old_name = rename.old_name;
17285        let new_name = rename.editor.read(cx).text(cx);
17286
17287        let rename = self.semantics_provider.as_ref()?.perform_rename(
17288            &buffer,
17289            start,
17290            new_name.clone(),
17291            cx,
17292        )?;
17293
17294        Some(cx.spawn_in(window, async move |editor, cx| {
17295            let project_transaction = rename.await?;
17296            Self::open_project_transaction(
17297                &editor,
17298                workspace,
17299                project_transaction,
17300                format!("Rename: {}{}", old_name, new_name),
17301                cx,
17302            )
17303            .await?;
17304
17305            editor.update(cx, |editor, cx| {
17306                editor.refresh_document_highlights(cx);
17307            })?;
17308            Ok(())
17309        }))
17310    }
17311
17312    fn take_rename(
17313        &mut self,
17314        moving_cursor: bool,
17315        window: &mut Window,
17316        cx: &mut Context<Self>,
17317    ) -> Option<RenameState> {
17318        let rename = self.pending_rename.take()?;
17319        if rename.editor.focus_handle(cx).is_focused(window) {
17320            window.focus(&self.focus_handle);
17321        }
17322
17323        self.remove_blocks(
17324            [rename.block_id].into_iter().collect(),
17325            Some(Autoscroll::fit()),
17326            cx,
17327        );
17328        self.clear_highlights::<Rename>(cx);
17329        self.show_local_selections = true;
17330
17331        if moving_cursor {
17332            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17333                editor
17334                    .selections
17335                    .newest::<usize>(&editor.display_snapshot(cx))
17336                    .head()
17337            });
17338
17339            // Update the selection to match the position of the selection inside
17340            // the rename editor.
17341            let snapshot = self.buffer.read(cx).read(cx);
17342            let rename_range = rename.range.to_offset(&snapshot);
17343            let cursor_in_editor = snapshot
17344                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17345                .min(rename_range.end);
17346            drop(snapshot);
17347
17348            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17349                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17350            });
17351        } else {
17352            self.refresh_document_highlights(cx);
17353        }
17354
17355        Some(rename)
17356    }
17357
17358    pub fn pending_rename(&self) -> Option<&RenameState> {
17359        self.pending_rename.as_ref()
17360    }
17361
17362    fn format(
17363        &mut self,
17364        _: &Format,
17365        window: &mut Window,
17366        cx: &mut Context<Self>,
17367    ) -> Option<Task<Result<()>>> {
17368        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17369
17370        let project = match &self.project {
17371            Some(project) => project.clone(),
17372            None => return None,
17373        };
17374
17375        Some(self.perform_format(
17376            project,
17377            FormatTrigger::Manual,
17378            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17379            window,
17380            cx,
17381        ))
17382    }
17383
17384    fn format_selections(
17385        &mut self,
17386        _: &FormatSelections,
17387        window: &mut Window,
17388        cx: &mut Context<Self>,
17389    ) -> Option<Task<Result<()>>> {
17390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17391
17392        let project = match &self.project {
17393            Some(project) => project.clone(),
17394            None => return None,
17395        };
17396
17397        let ranges = self
17398            .selections
17399            .all_adjusted(&self.display_snapshot(cx))
17400            .into_iter()
17401            .map(|selection| selection.range())
17402            .collect_vec();
17403
17404        Some(self.perform_format(
17405            project,
17406            FormatTrigger::Manual,
17407            FormatTarget::Ranges(ranges),
17408            window,
17409            cx,
17410        ))
17411    }
17412
17413    fn perform_format(
17414        &mut self,
17415        project: Entity<Project>,
17416        trigger: FormatTrigger,
17417        target: FormatTarget,
17418        window: &mut Window,
17419        cx: &mut Context<Self>,
17420    ) -> Task<Result<()>> {
17421        let buffer = self.buffer.clone();
17422        let (buffers, target) = match target {
17423            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17424            FormatTarget::Ranges(selection_ranges) => {
17425                let multi_buffer = buffer.read(cx);
17426                let snapshot = multi_buffer.read(cx);
17427                let mut buffers = HashSet::default();
17428                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17429                    BTreeMap::new();
17430                for selection_range in selection_ranges {
17431                    for (buffer, buffer_range, _) in
17432                        snapshot.range_to_buffer_ranges(selection_range)
17433                    {
17434                        let buffer_id = buffer.remote_id();
17435                        let start = buffer.anchor_before(buffer_range.start);
17436                        let end = buffer.anchor_after(buffer_range.end);
17437                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17438                        buffer_id_to_ranges
17439                            .entry(buffer_id)
17440                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17441                            .or_insert_with(|| vec![start..end]);
17442                    }
17443                }
17444                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17445            }
17446        };
17447
17448        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17449        let selections_prev = transaction_id_prev
17450            .and_then(|transaction_id_prev| {
17451                // default to selections as they were after the last edit, if we have them,
17452                // instead of how they are now.
17453                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17454                // will take you back to where you made the last edit, instead of staying where you scrolled
17455                self.selection_history
17456                    .transaction(transaction_id_prev)
17457                    .map(|t| t.0.clone())
17458            })
17459            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17460
17461        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17462        let format = project.update(cx, |project, cx| {
17463            project.format(buffers, target, true, trigger, cx)
17464        });
17465
17466        cx.spawn_in(window, async move |editor, cx| {
17467            let transaction = futures::select_biased! {
17468                transaction = format.log_err().fuse() => transaction,
17469                () = timeout => {
17470                    log::warn!("timed out waiting for formatting");
17471                    None
17472                }
17473            };
17474
17475            buffer
17476                .update(cx, |buffer, cx| {
17477                    if let Some(transaction) = transaction
17478                        && !buffer.is_singleton()
17479                    {
17480                        buffer.push_transaction(&transaction.0, cx);
17481                    }
17482                    cx.notify();
17483                })
17484                .ok();
17485
17486            if let Some(transaction_id_now) =
17487                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17488            {
17489                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17490                if has_new_transaction {
17491                    _ = editor.update(cx, |editor, _| {
17492                        editor
17493                            .selection_history
17494                            .insert_transaction(transaction_id_now, selections_prev);
17495                    });
17496                }
17497            }
17498
17499            Ok(())
17500        })
17501    }
17502
17503    fn organize_imports(
17504        &mut self,
17505        _: &OrganizeImports,
17506        window: &mut Window,
17507        cx: &mut Context<Self>,
17508    ) -> Option<Task<Result<()>>> {
17509        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17510        let project = match &self.project {
17511            Some(project) => project.clone(),
17512            None => return None,
17513        };
17514        Some(self.perform_code_action_kind(
17515            project,
17516            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17517            window,
17518            cx,
17519        ))
17520    }
17521
17522    fn perform_code_action_kind(
17523        &mut self,
17524        project: Entity<Project>,
17525        kind: CodeActionKind,
17526        window: &mut Window,
17527        cx: &mut Context<Self>,
17528    ) -> Task<Result<()>> {
17529        let buffer = self.buffer.clone();
17530        let buffers = buffer.read(cx).all_buffers();
17531        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17532        let apply_action = project.update(cx, |project, cx| {
17533            project.apply_code_action_kind(buffers, kind, true, cx)
17534        });
17535        cx.spawn_in(window, async move |_, cx| {
17536            let transaction = futures::select_biased! {
17537                () = timeout => {
17538                    log::warn!("timed out waiting for executing code action");
17539                    None
17540                }
17541                transaction = apply_action.log_err().fuse() => transaction,
17542            };
17543            buffer
17544                .update(cx, |buffer, cx| {
17545                    // check if we need this
17546                    if let Some(transaction) = transaction
17547                        && !buffer.is_singleton()
17548                    {
17549                        buffer.push_transaction(&transaction.0, cx);
17550                    }
17551                    cx.notify();
17552                })
17553                .ok();
17554            Ok(())
17555        })
17556    }
17557
17558    pub fn restart_language_server(
17559        &mut self,
17560        _: &RestartLanguageServer,
17561        _: &mut Window,
17562        cx: &mut Context<Self>,
17563    ) {
17564        if let Some(project) = self.project.clone() {
17565            self.buffer.update(cx, |multi_buffer, cx| {
17566                project.update(cx, |project, cx| {
17567                    project.restart_language_servers_for_buffers(
17568                        multi_buffer.all_buffers().into_iter().collect(),
17569                        HashSet::default(),
17570                        cx,
17571                    );
17572                });
17573            })
17574        }
17575    }
17576
17577    pub fn stop_language_server(
17578        &mut self,
17579        _: &StopLanguageServer,
17580        _: &mut Window,
17581        cx: &mut Context<Self>,
17582    ) {
17583        if let Some(project) = self.project.clone() {
17584            self.buffer.update(cx, |multi_buffer, cx| {
17585                project.update(cx, |project, cx| {
17586                    project.stop_language_servers_for_buffers(
17587                        multi_buffer.all_buffers().into_iter().collect(),
17588                        HashSet::default(),
17589                        cx,
17590                    );
17591                    cx.emit(project::Event::RefreshInlayHints);
17592                });
17593            });
17594        }
17595    }
17596
17597    fn cancel_language_server_work(
17598        workspace: &mut Workspace,
17599        _: &actions::CancelLanguageServerWork,
17600        _: &mut Window,
17601        cx: &mut Context<Workspace>,
17602    ) {
17603        let project = workspace.project();
17604        let buffers = workspace
17605            .active_item(cx)
17606            .and_then(|item| item.act_as::<Editor>(cx))
17607            .map_or(HashSet::default(), |editor| {
17608                editor.read(cx).buffer.read(cx).all_buffers()
17609            });
17610        project.update(cx, |project, cx| {
17611            project.cancel_language_server_work_for_buffers(buffers, cx);
17612        });
17613    }
17614
17615    fn show_character_palette(
17616        &mut self,
17617        _: &ShowCharacterPalette,
17618        window: &mut Window,
17619        _: &mut Context<Self>,
17620    ) {
17621        window.show_character_palette();
17622    }
17623
17624    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17625        if !self.diagnostics_enabled() {
17626            return;
17627        }
17628
17629        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17630            let buffer = self.buffer.read(cx).snapshot(cx);
17631            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17632            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17633            let is_valid = buffer
17634                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17635                .any(|entry| {
17636                    entry.diagnostic.is_primary
17637                        && !entry.range.is_empty()
17638                        && entry.range.start == primary_range_start
17639                        && entry.diagnostic.message == active_diagnostics.active_message
17640                });
17641
17642            if !is_valid {
17643                self.dismiss_diagnostics(cx);
17644            }
17645        }
17646    }
17647
17648    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17649        match &self.active_diagnostics {
17650            ActiveDiagnostic::Group(group) => Some(group),
17651            _ => None,
17652        }
17653    }
17654
17655    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17656        if !self.diagnostics_enabled() {
17657            return;
17658        }
17659        self.dismiss_diagnostics(cx);
17660        self.active_diagnostics = ActiveDiagnostic::All;
17661    }
17662
17663    fn activate_diagnostics(
17664        &mut self,
17665        buffer_id: BufferId,
17666        diagnostic: DiagnosticEntryRef<'_, usize>,
17667        window: &mut Window,
17668        cx: &mut Context<Self>,
17669    ) {
17670        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17671            return;
17672        }
17673        self.dismiss_diagnostics(cx);
17674        let snapshot = self.snapshot(window, cx);
17675        let buffer = self.buffer.read(cx).snapshot(cx);
17676        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17677            return;
17678        };
17679
17680        let diagnostic_group = buffer
17681            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17682            .collect::<Vec<_>>();
17683
17684        let blocks =
17685            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17686
17687        let blocks = self.display_map.update(cx, |display_map, cx| {
17688            display_map.insert_blocks(blocks, cx).into_iter().collect()
17689        });
17690        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17691            active_range: buffer.anchor_before(diagnostic.range.start)
17692                ..buffer.anchor_after(diagnostic.range.end),
17693            active_message: diagnostic.diagnostic.message.clone(),
17694            group_id: diagnostic.diagnostic.group_id,
17695            blocks,
17696        });
17697        cx.notify();
17698    }
17699
17700    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17701        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17702            return;
17703        };
17704
17705        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17706        if let ActiveDiagnostic::Group(group) = prev {
17707            self.display_map.update(cx, |display_map, cx| {
17708                display_map.remove_blocks(group.blocks, cx);
17709            });
17710            cx.notify();
17711        }
17712    }
17713
17714    /// Disable inline diagnostics rendering for this editor.
17715    pub fn disable_inline_diagnostics(&mut self) {
17716        self.inline_diagnostics_enabled = false;
17717        self.inline_diagnostics_update = Task::ready(());
17718        self.inline_diagnostics.clear();
17719    }
17720
17721    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17722        self.diagnostics_enabled = false;
17723        self.dismiss_diagnostics(cx);
17724        self.inline_diagnostics_update = Task::ready(());
17725        self.inline_diagnostics.clear();
17726    }
17727
17728    pub fn disable_word_completions(&mut self) {
17729        self.word_completions_enabled = false;
17730    }
17731
17732    pub fn diagnostics_enabled(&self) -> bool {
17733        self.diagnostics_enabled && self.mode.is_full()
17734    }
17735
17736    pub fn inline_diagnostics_enabled(&self) -> bool {
17737        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17738    }
17739
17740    pub fn show_inline_diagnostics(&self) -> bool {
17741        self.show_inline_diagnostics
17742    }
17743
17744    pub fn toggle_inline_diagnostics(
17745        &mut self,
17746        _: &ToggleInlineDiagnostics,
17747        window: &mut Window,
17748        cx: &mut Context<Editor>,
17749    ) {
17750        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17751        self.refresh_inline_diagnostics(false, window, cx);
17752    }
17753
17754    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17755        self.diagnostics_max_severity = severity;
17756        self.display_map.update(cx, |display_map, _| {
17757            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17758        });
17759    }
17760
17761    pub fn toggle_diagnostics(
17762        &mut self,
17763        _: &ToggleDiagnostics,
17764        window: &mut Window,
17765        cx: &mut Context<Editor>,
17766    ) {
17767        if !self.diagnostics_enabled() {
17768            return;
17769        }
17770
17771        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17772            EditorSettings::get_global(cx)
17773                .diagnostics_max_severity
17774                .filter(|severity| severity != &DiagnosticSeverity::Off)
17775                .unwrap_or(DiagnosticSeverity::Hint)
17776        } else {
17777            DiagnosticSeverity::Off
17778        };
17779        self.set_max_diagnostics_severity(new_severity, cx);
17780        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17781            self.active_diagnostics = ActiveDiagnostic::None;
17782            self.inline_diagnostics_update = Task::ready(());
17783            self.inline_diagnostics.clear();
17784        } else {
17785            self.refresh_inline_diagnostics(false, window, cx);
17786        }
17787
17788        cx.notify();
17789    }
17790
17791    pub fn toggle_minimap(
17792        &mut self,
17793        _: &ToggleMinimap,
17794        window: &mut Window,
17795        cx: &mut Context<Editor>,
17796    ) {
17797        if self.supports_minimap(cx) {
17798            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17799        }
17800    }
17801
17802    fn refresh_inline_diagnostics(
17803        &mut self,
17804        debounce: bool,
17805        window: &mut Window,
17806        cx: &mut Context<Self>,
17807    ) {
17808        let max_severity = ProjectSettings::get_global(cx)
17809            .diagnostics
17810            .inline
17811            .max_severity
17812            .unwrap_or(self.diagnostics_max_severity);
17813
17814        if !self.inline_diagnostics_enabled()
17815            || !self.show_inline_diagnostics
17816            || max_severity == DiagnosticSeverity::Off
17817        {
17818            self.inline_diagnostics_update = Task::ready(());
17819            self.inline_diagnostics.clear();
17820            return;
17821        }
17822
17823        let debounce_ms = ProjectSettings::get_global(cx)
17824            .diagnostics
17825            .inline
17826            .update_debounce_ms;
17827        let debounce = if debounce && debounce_ms > 0 {
17828            Some(Duration::from_millis(debounce_ms))
17829        } else {
17830            None
17831        };
17832        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17833            if let Some(debounce) = debounce {
17834                cx.background_executor().timer(debounce).await;
17835            }
17836            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17837                editor
17838                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17839                    .ok()
17840            }) else {
17841                return;
17842            };
17843
17844            let new_inline_diagnostics = cx
17845                .background_spawn(async move {
17846                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17847                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17848                        let message = diagnostic_entry
17849                            .diagnostic
17850                            .message
17851                            .split_once('\n')
17852                            .map(|(line, _)| line)
17853                            .map(SharedString::new)
17854                            .unwrap_or_else(|| {
17855                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17856                            });
17857                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17858                        let (Ok(i) | Err(i)) = inline_diagnostics
17859                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17860                        inline_diagnostics.insert(
17861                            i,
17862                            (
17863                                start_anchor,
17864                                InlineDiagnostic {
17865                                    message,
17866                                    group_id: diagnostic_entry.diagnostic.group_id,
17867                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17868                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17869                                    severity: diagnostic_entry.diagnostic.severity,
17870                                },
17871                            ),
17872                        );
17873                    }
17874                    inline_diagnostics
17875                })
17876                .await;
17877
17878            editor
17879                .update(cx, |editor, cx| {
17880                    editor.inline_diagnostics = new_inline_diagnostics;
17881                    cx.notify();
17882                })
17883                .ok();
17884        });
17885    }
17886
17887    fn pull_diagnostics(
17888        &mut self,
17889        buffer_id: Option<BufferId>,
17890        window: &Window,
17891        cx: &mut Context<Self>,
17892    ) -> Option<()> {
17893        if self.ignore_lsp_data() {
17894            return None;
17895        }
17896        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17897            .diagnostics
17898            .lsp_pull_diagnostics;
17899        if !pull_diagnostics_settings.enabled {
17900            return None;
17901        }
17902        let project = self.project()?.downgrade();
17903        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17904        let mut buffers = self.buffer.read(cx).all_buffers();
17905        buffers.retain(|buffer| {
17906            let buffer_id_to_retain = buffer.read(cx).remote_id();
17907            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17908                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17909        });
17910        if buffers.is_empty() {
17911            self.pull_diagnostics_task = Task::ready(());
17912            return None;
17913        }
17914
17915        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17916            cx.background_executor().timer(debounce).await;
17917
17918            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17919                buffers
17920                    .into_iter()
17921                    .filter_map(|buffer| {
17922                        project
17923                            .update(cx, |project, cx| {
17924                                project.lsp_store().update(cx, |lsp_store, cx| {
17925                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17926                                })
17927                            })
17928                            .ok()
17929                    })
17930                    .collect::<FuturesUnordered<_>>()
17931            }) else {
17932                return;
17933            };
17934
17935            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17936                match pull_task {
17937                    Ok(()) => {
17938                        if editor
17939                            .update_in(cx, |editor, window, cx| {
17940                                editor.update_diagnostics_state(window, cx);
17941                            })
17942                            .is_err()
17943                        {
17944                            return;
17945                        }
17946                    }
17947                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17948                }
17949            }
17950        });
17951
17952        Some(())
17953    }
17954
17955    pub fn set_selections_from_remote(
17956        &mut self,
17957        selections: Vec<Selection<Anchor>>,
17958        pending_selection: Option<Selection<Anchor>>,
17959        window: &mut Window,
17960        cx: &mut Context<Self>,
17961    ) {
17962        let old_cursor_position = self.selections.newest_anchor().head();
17963        self.selections.change_with(cx, |s| {
17964            s.select_anchors(selections);
17965            if let Some(pending_selection) = pending_selection {
17966                s.set_pending(pending_selection, SelectMode::Character);
17967            } else {
17968                s.clear_pending();
17969            }
17970        });
17971        self.selections_did_change(
17972            false,
17973            &old_cursor_position,
17974            SelectionEffects::default(),
17975            window,
17976            cx,
17977        );
17978    }
17979
17980    pub fn transact(
17981        &mut self,
17982        window: &mut Window,
17983        cx: &mut Context<Self>,
17984        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17985    ) -> Option<TransactionId> {
17986        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17987            this.start_transaction_at(Instant::now(), window, cx);
17988            update(this, window, cx);
17989            this.end_transaction_at(Instant::now(), cx)
17990        })
17991    }
17992
17993    pub fn start_transaction_at(
17994        &mut self,
17995        now: Instant,
17996        window: &mut Window,
17997        cx: &mut Context<Self>,
17998    ) -> Option<TransactionId> {
17999        self.end_selection(window, cx);
18000        if let Some(tx_id) = self
18001            .buffer
18002            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18003        {
18004            self.selection_history
18005                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18006            cx.emit(EditorEvent::TransactionBegun {
18007                transaction_id: tx_id,
18008            });
18009            Some(tx_id)
18010        } else {
18011            None
18012        }
18013    }
18014
18015    pub fn end_transaction_at(
18016        &mut self,
18017        now: Instant,
18018        cx: &mut Context<Self>,
18019    ) -> Option<TransactionId> {
18020        if let Some(transaction_id) = self
18021            .buffer
18022            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18023        {
18024            if let Some((_, end_selections)) =
18025                self.selection_history.transaction_mut(transaction_id)
18026            {
18027                *end_selections = Some(self.selections.disjoint_anchors_arc());
18028            } else {
18029                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18030            }
18031
18032            cx.emit(EditorEvent::Edited { transaction_id });
18033            Some(transaction_id)
18034        } else {
18035            None
18036        }
18037    }
18038
18039    pub fn modify_transaction_selection_history(
18040        &mut self,
18041        transaction_id: TransactionId,
18042        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18043    ) -> bool {
18044        self.selection_history
18045            .transaction_mut(transaction_id)
18046            .map(modify)
18047            .is_some()
18048    }
18049
18050    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18051        if self.selection_mark_mode {
18052            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18053                s.move_with(|_, sel| {
18054                    sel.collapse_to(sel.head(), SelectionGoal::None);
18055                });
18056            })
18057        }
18058        self.selection_mark_mode = true;
18059        cx.notify();
18060    }
18061
18062    pub fn swap_selection_ends(
18063        &mut self,
18064        _: &actions::SwapSelectionEnds,
18065        window: &mut Window,
18066        cx: &mut Context<Self>,
18067    ) {
18068        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18069            s.move_with(|_, sel| {
18070                if sel.start != sel.end {
18071                    sel.reversed = !sel.reversed
18072                }
18073            });
18074        });
18075        self.request_autoscroll(Autoscroll::newest(), cx);
18076        cx.notify();
18077    }
18078
18079    pub fn toggle_focus(
18080        workspace: &mut Workspace,
18081        _: &actions::ToggleFocus,
18082        window: &mut Window,
18083        cx: &mut Context<Workspace>,
18084    ) {
18085        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18086            return;
18087        };
18088        workspace.activate_item(&item, true, true, window, cx);
18089    }
18090
18091    pub fn toggle_fold(
18092        &mut self,
18093        _: &actions::ToggleFold,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) {
18097        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18098            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18099            let selection = self.selections.newest::<Point>(&display_map);
18100
18101            let range = if selection.is_empty() {
18102                let point = selection.head().to_display_point(&display_map);
18103                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18104                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18105                    .to_point(&display_map);
18106                start..end
18107            } else {
18108                selection.range()
18109            };
18110            if display_map.folds_in_range(range).next().is_some() {
18111                self.unfold_lines(&Default::default(), window, cx)
18112            } else {
18113                self.fold(&Default::default(), window, cx)
18114            }
18115        } else {
18116            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18117            let buffer_ids: HashSet<_> = self
18118                .selections
18119                .disjoint_anchor_ranges()
18120                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18121                .collect();
18122
18123            let should_unfold = buffer_ids
18124                .iter()
18125                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18126
18127            for buffer_id in buffer_ids {
18128                if should_unfold {
18129                    self.unfold_buffer(buffer_id, cx);
18130                } else {
18131                    self.fold_buffer(buffer_id, cx);
18132                }
18133            }
18134        }
18135    }
18136
18137    pub fn toggle_fold_recursive(
18138        &mut self,
18139        _: &actions::ToggleFoldRecursive,
18140        window: &mut Window,
18141        cx: &mut Context<Self>,
18142    ) {
18143        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18144
18145        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18146        let range = if selection.is_empty() {
18147            let point = selection.head().to_display_point(&display_map);
18148            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18149            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18150                .to_point(&display_map);
18151            start..end
18152        } else {
18153            selection.range()
18154        };
18155        if display_map.folds_in_range(range).next().is_some() {
18156            self.unfold_recursive(&Default::default(), window, cx)
18157        } else {
18158            self.fold_recursive(&Default::default(), window, cx)
18159        }
18160    }
18161
18162    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18163        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18164            let mut to_fold = Vec::new();
18165            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18166            let selections = self.selections.all_adjusted(&display_map);
18167
18168            for selection in selections {
18169                let range = selection.range().sorted();
18170                let buffer_start_row = range.start.row;
18171
18172                if range.start.row != range.end.row {
18173                    let mut found = false;
18174                    let mut row = range.start.row;
18175                    while row <= range.end.row {
18176                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18177                        {
18178                            found = true;
18179                            row = crease.range().end.row + 1;
18180                            to_fold.push(crease);
18181                        } else {
18182                            row += 1
18183                        }
18184                    }
18185                    if found {
18186                        continue;
18187                    }
18188                }
18189
18190                for row in (0..=range.start.row).rev() {
18191                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18192                        && crease.range().end.row >= buffer_start_row
18193                    {
18194                        to_fold.push(crease);
18195                        if row <= range.start.row {
18196                            break;
18197                        }
18198                    }
18199                }
18200            }
18201
18202            self.fold_creases(to_fold, true, window, cx);
18203        } else {
18204            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18205            let buffer_ids = self
18206                .selections
18207                .disjoint_anchor_ranges()
18208                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18209                .collect::<HashSet<_>>();
18210            for buffer_id in buffer_ids {
18211                self.fold_buffer(buffer_id, cx);
18212            }
18213        }
18214    }
18215
18216    pub fn toggle_fold_all(
18217        &mut self,
18218        _: &actions::ToggleFoldAll,
18219        window: &mut Window,
18220        cx: &mut Context<Self>,
18221    ) {
18222        if self.buffer.read(cx).is_singleton() {
18223            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18224            let has_folds = display_map
18225                .folds_in_range(0..display_map.buffer_snapshot().len())
18226                .next()
18227                .is_some();
18228
18229            if has_folds {
18230                self.unfold_all(&actions::UnfoldAll, window, cx);
18231            } else {
18232                self.fold_all(&actions::FoldAll, window, cx);
18233            }
18234        } else {
18235            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18236            let should_unfold = buffer_ids
18237                .iter()
18238                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18239
18240            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18241                editor
18242                    .update_in(cx, |editor, _, cx| {
18243                        for buffer_id in buffer_ids {
18244                            if should_unfold {
18245                                editor.unfold_buffer(buffer_id, cx);
18246                            } else {
18247                                editor.fold_buffer(buffer_id, cx);
18248                            }
18249                        }
18250                    })
18251                    .ok();
18252            });
18253        }
18254    }
18255
18256    fn fold_at_level(
18257        &mut self,
18258        fold_at: &FoldAtLevel,
18259        window: &mut Window,
18260        cx: &mut Context<Self>,
18261    ) {
18262        if !self.buffer.read(cx).is_singleton() {
18263            return;
18264        }
18265
18266        let fold_at_level = fold_at.0;
18267        let snapshot = self.buffer.read(cx).snapshot(cx);
18268        let mut to_fold = Vec::new();
18269        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18270
18271        let row_ranges_to_keep: Vec<Range<u32>> = self
18272            .selections
18273            .all::<Point>(&self.display_snapshot(cx))
18274            .into_iter()
18275            .map(|sel| sel.start.row..sel.end.row)
18276            .collect();
18277
18278        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18279            while start_row < end_row {
18280                match self
18281                    .snapshot(window, cx)
18282                    .crease_for_buffer_row(MultiBufferRow(start_row))
18283                {
18284                    Some(crease) => {
18285                        let nested_start_row = crease.range().start.row + 1;
18286                        let nested_end_row = crease.range().end.row;
18287
18288                        if current_level < fold_at_level {
18289                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18290                        } else if current_level == fold_at_level {
18291                            // Fold iff there is no selection completely contained within the fold region
18292                            if !row_ranges_to_keep.iter().any(|selection| {
18293                                selection.end >= nested_start_row
18294                                    && selection.start <= nested_end_row
18295                            }) {
18296                                to_fold.push(crease);
18297                            }
18298                        }
18299
18300                        start_row = nested_end_row + 1;
18301                    }
18302                    None => start_row += 1,
18303                }
18304            }
18305        }
18306
18307        self.fold_creases(to_fold, true, window, cx);
18308    }
18309
18310    pub fn fold_at_level_1(
18311        &mut self,
18312        _: &actions::FoldAtLevel1,
18313        window: &mut Window,
18314        cx: &mut Context<Self>,
18315    ) {
18316        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18317    }
18318
18319    pub fn fold_at_level_2(
18320        &mut self,
18321        _: &actions::FoldAtLevel2,
18322        window: &mut Window,
18323        cx: &mut Context<Self>,
18324    ) {
18325        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18326    }
18327
18328    pub fn fold_at_level_3(
18329        &mut self,
18330        _: &actions::FoldAtLevel3,
18331        window: &mut Window,
18332        cx: &mut Context<Self>,
18333    ) {
18334        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18335    }
18336
18337    pub fn fold_at_level_4(
18338        &mut self,
18339        _: &actions::FoldAtLevel4,
18340        window: &mut Window,
18341        cx: &mut Context<Self>,
18342    ) {
18343        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18344    }
18345
18346    pub fn fold_at_level_5(
18347        &mut self,
18348        _: &actions::FoldAtLevel5,
18349        window: &mut Window,
18350        cx: &mut Context<Self>,
18351    ) {
18352        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18353    }
18354
18355    pub fn fold_at_level_6(
18356        &mut self,
18357        _: &actions::FoldAtLevel6,
18358        window: &mut Window,
18359        cx: &mut Context<Self>,
18360    ) {
18361        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18362    }
18363
18364    pub fn fold_at_level_7(
18365        &mut self,
18366        _: &actions::FoldAtLevel7,
18367        window: &mut Window,
18368        cx: &mut Context<Self>,
18369    ) {
18370        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18371    }
18372
18373    pub fn fold_at_level_8(
18374        &mut self,
18375        _: &actions::FoldAtLevel8,
18376        window: &mut Window,
18377        cx: &mut Context<Self>,
18378    ) {
18379        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18380    }
18381
18382    pub fn fold_at_level_9(
18383        &mut self,
18384        _: &actions::FoldAtLevel9,
18385        window: &mut Window,
18386        cx: &mut Context<Self>,
18387    ) {
18388        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18389    }
18390
18391    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18392        if self.buffer.read(cx).is_singleton() {
18393            let mut fold_ranges = Vec::new();
18394            let snapshot = self.buffer.read(cx).snapshot(cx);
18395
18396            for row in 0..snapshot.max_row().0 {
18397                if let Some(foldable_range) = self
18398                    .snapshot(window, cx)
18399                    .crease_for_buffer_row(MultiBufferRow(row))
18400                {
18401                    fold_ranges.push(foldable_range);
18402                }
18403            }
18404
18405            self.fold_creases(fold_ranges, true, window, cx);
18406        } else {
18407            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18408                editor
18409                    .update_in(cx, |editor, _, cx| {
18410                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18411                            editor.fold_buffer(buffer_id, cx);
18412                        }
18413                    })
18414                    .ok();
18415            });
18416        }
18417    }
18418
18419    pub fn fold_function_bodies(
18420        &mut self,
18421        _: &actions::FoldFunctionBodies,
18422        window: &mut Window,
18423        cx: &mut Context<Self>,
18424    ) {
18425        let snapshot = self.buffer.read(cx).snapshot(cx);
18426
18427        let ranges = snapshot
18428            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18429            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18430            .collect::<Vec<_>>();
18431
18432        let creases = ranges
18433            .into_iter()
18434            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18435            .collect();
18436
18437        self.fold_creases(creases, true, window, cx);
18438    }
18439
18440    pub fn fold_recursive(
18441        &mut self,
18442        _: &actions::FoldRecursive,
18443        window: &mut Window,
18444        cx: &mut Context<Self>,
18445    ) {
18446        let mut to_fold = Vec::new();
18447        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18448        let selections = self.selections.all_adjusted(&display_map);
18449
18450        for selection in selections {
18451            let range = selection.range().sorted();
18452            let buffer_start_row = range.start.row;
18453
18454            if range.start.row != range.end.row {
18455                let mut found = false;
18456                for row in range.start.row..=range.end.row {
18457                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18458                        found = true;
18459                        to_fold.push(crease);
18460                    }
18461                }
18462                if found {
18463                    continue;
18464                }
18465            }
18466
18467            for row in (0..=range.start.row).rev() {
18468                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18469                    if crease.range().end.row >= buffer_start_row {
18470                        to_fold.push(crease);
18471                    } else {
18472                        break;
18473                    }
18474                }
18475            }
18476        }
18477
18478        self.fold_creases(to_fold, true, window, cx);
18479    }
18480
18481    pub fn fold_at(
18482        &mut self,
18483        buffer_row: MultiBufferRow,
18484        window: &mut Window,
18485        cx: &mut Context<Self>,
18486    ) {
18487        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18488
18489        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18490            let autoscroll = self
18491                .selections
18492                .all::<Point>(&display_map)
18493                .iter()
18494                .any(|selection| crease.range().overlaps(&selection.range()));
18495
18496            self.fold_creases(vec![crease], autoscroll, window, cx);
18497        }
18498    }
18499
18500    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18501        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18502            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18503            let buffer = display_map.buffer_snapshot();
18504            let selections = self.selections.all::<Point>(&display_map);
18505            let ranges = selections
18506                .iter()
18507                .map(|s| {
18508                    let range = s.display_range(&display_map).sorted();
18509                    let mut start = range.start.to_point(&display_map);
18510                    let mut end = range.end.to_point(&display_map);
18511                    start.column = 0;
18512                    end.column = buffer.line_len(MultiBufferRow(end.row));
18513                    start..end
18514                })
18515                .collect::<Vec<_>>();
18516
18517            self.unfold_ranges(&ranges, true, true, cx);
18518        } else {
18519            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18520            let buffer_ids = self
18521                .selections
18522                .disjoint_anchor_ranges()
18523                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18524                .collect::<HashSet<_>>();
18525            for buffer_id in buffer_ids {
18526                self.unfold_buffer(buffer_id, cx);
18527            }
18528        }
18529    }
18530
18531    pub fn unfold_recursive(
18532        &mut self,
18533        _: &UnfoldRecursive,
18534        _window: &mut Window,
18535        cx: &mut Context<Self>,
18536    ) {
18537        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18538        let selections = self.selections.all::<Point>(&display_map);
18539        let ranges = selections
18540            .iter()
18541            .map(|s| {
18542                let mut range = s.display_range(&display_map).sorted();
18543                *range.start.column_mut() = 0;
18544                *range.end.column_mut() = display_map.line_len(range.end.row());
18545                let start = range.start.to_point(&display_map);
18546                let end = range.end.to_point(&display_map);
18547                start..end
18548            })
18549            .collect::<Vec<_>>();
18550
18551        self.unfold_ranges(&ranges, true, true, cx);
18552    }
18553
18554    pub fn unfold_at(
18555        &mut self,
18556        buffer_row: MultiBufferRow,
18557        _window: &mut Window,
18558        cx: &mut Context<Self>,
18559    ) {
18560        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18561
18562        let intersection_range = Point::new(buffer_row.0, 0)
18563            ..Point::new(
18564                buffer_row.0,
18565                display_map.buffer_snapshot().line_len(buffer_row),
18566            );
18567
18568        let autoscroll = self
18569            .selections
18570            .all::<Point>(&display_map)
18571            .iter()
18572            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18573
18574        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18575    }
18576
18577    pub fn unfold_all(
18578        &mut self,
18579        _: &actions::UnfoldAll,
18580        _window: &mut Window,
18581        cx: &mut Context<Self>,
18582    ) {
18583        if self.buffer.read(cx).is_singleton() {
18584            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18585            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18586        } else {
18587            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18588                editor
18589                    .update(cx, |editor, cx| {
18590                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18591                            editor.unfold_buffer(buffer_id, cx);
18592                        }
18593                    })
18594                    .ok();
18595            });
18596        }
18597    }
18598
18599    pub fn fold_selected_ranges(
18600        &mut self,
18601        _: &FoldSelectedRanges,
18602        window: &mut Window,
18603        cx: &mut Context<Self>,
18604    ) {
18605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18606        let selections = self.selections.all_adjusted(&display_map);
18607        let ranges = selections
18608            .into_iter()
18609            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18610            .collect::<Vec<_>>();
18611        self.fold_creases(ranges, true, window, cx);
18612    }
18613
18614    pub fn fold_ranges<T: ToOffset + Clone>(
18615        &mut self,
18616        ranges: Vec<Range<T>>,
18617        auto_scroll: bool,
18618        window: &mut Window,
18619        cx: &mut Context<Self>,
18620    ) {
18621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18622        let ranges = ranges
18623            .into_iter()
18624            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18625            .collect::<Vec<_>>();
18626        self.fold_creases(ranges, auto_scroll, window, cx);
18627    }
18628
18629    pub fn fold_creases<T: ToOffset + Clone>(
18630        &mut self,
18631        creases: Vec<Crease<T>>,
18632        auto_scroll: bool,
18633        _window: &mut Window,
18634        cx: &mut Context<Self>,
18635    ) {
18636        if creases.is_empty() {
18637            return;
18638        }
18639
18640        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18641
18642        if auto_scroll {
18643            self.request_autoscroll(Autoscroll::fit(), cx);
18644        }
18645
18646        cx.notify();
18647
18648        self.scrollbar_marker_state.dirty = true;
18649        self.folds_did_change(cx);
18650    }
18651
18652    /// Removes any folds whose ranges intersect any of the given ranges.
18653    pub fn unfold_ranges<T: ToOffset + Clone>(
18654        &mut self,
18655        ranges: &[Range<T>],
18656        inclusive: bool,
18657        auto_scroll: bool,
18658        cx: &mut Context<Self>,
18659    ) {
18660        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18661            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18662        });
18663        self.folds_did_change(cx);
18664    }
18665
18666    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18667        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18668            return;
18669        }
18670        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18671        self.display_map.update(cx, |display_map, cx| {
18672            display_map.fold_buffers([buffer_id], cx)
18673        });
18674        cx.emit(EditorEvent::BufferFoldToggled {
18675            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18676            folded: true,
18677        });
18678        cx.notify();
18679    }
18680
18681    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18682        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18683            return;
18684        }
18685        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18686        self.display_map.update(cx, |display_map, cx| {
18687            display_map.unfold_buffers([buffer_id], cx);
18688        });
18689        cx.emit(EditorEvent::BufferFoldToggled {
18690            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18691            folded: false,
18692        });
18693        cx.notify();
18694    }
18695
18696    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18697        self.display_map.read(cx).is_buffer_folded(buffer)
18698    }
18699
18700    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18701        self.display_map.read(cx).folded_buffers()
18702    }
18703
18704    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18705        self.display_map.update(cx, |display_map, cx| {
18706            display_map.disable_header_for_buffer(buffer_id, cx);
18707        });
18708        cx.notify();
18709    }
18710
18711    /// Removes any folds with the given ranges.
18712    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18713        &mut self,
18714        ranges: &[Range<T>],
18715        type_id: TypeId,
18716        auto_scroll: bool,
18717        cx: &mut Context<Self>,
18718    ) {
18719        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18720            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18721        });
18722        self.folds_did_change(cx);
18723    }
18724
18725    fn remove_folds_with<T: ToOffset + Clone>(
18726        &mut self,
18727        ranges: &[Range<T>],
18728        auto_scroll: bool,
18729        cx: &mut Context<Self>,
18730        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18731    ) {
18732        if ranges.is_empty() {
18733            return;
18734        }
18735
18736        let mut buffers_affected = HashSet::default();
18737        let multi_buffer = self.buffer().read(cx);
18738        for range in ranges {
18739            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18740                buffers_affected.insert(buffer.read(cx).remote_id());
18741            };
18742        }
18743
18744        self.display_map.update(cx, update);
18745
18746        if auto_scroll {
18747            self.request_autoscroll(Autoscroll::fit(), cx);
18748        }
18749
18750        cx.notify();
18751        self.scrollbar_marker_state.dirty = true;
18752        self.active_indent_guides_state.dirty = true;
18753    }
18754
18755    pub fn update_renderer_widths(
18756        &mut self,
18757        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18758        cx: &mut Context<Self>,
18759    ) -> bool {
18760        self.display_map
18761            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18762    }
18763
18764    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18765        self.display_map.read(cx).fold_placeholder.clone()
18766    }
18767
18768    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18769        self.buffer.update(cx, |buffer, cx| {
18770            buffer.set_all_diff_hunks_expanded(cx);
18771        });
18772    }
18773
18774    pub fn expand_all_diff_hunks(
18775        &mut self,
18776        _: &ExpandAllDiffHunks,
18777        _window: &mut Window,
18778        cx: &mut Context<Self>,
18779    ) {
18780        self.buffer.update(cx, |buffer, cx| {
18781            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18782        });
18783    }
18784
18785    pub fn toggle_selected_diff_hunks(
18786        &mut self,
18787        _: &ToggleSelectedDiffHunks,
18788        _window: &mut Window,
18789        cx: &mut Context<Self>,
18790    ) {
18791        let ranges: Vec<_> = self
18792            .selections
18793            .disjoint_anchors()
18794            .iter()
18795            .map(|s| s.range())
18796            .collect();
18797        self.toggle_diff_hunks_in_ranges(ranges, cx);
18798    }
18799
18800    pub fn diff_hunks_in_ranges<'a>(
18801        &'a self,
18802        ranges: &'a [Range<Anchor>],
18803        buffer: &'a MultiBufferSnapshot,
18804    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18805        ranges.iter().flat_map(move |range| {
18806            let end_excerpt_id = range.end.excerpt_id;
18807            let range = range.to_point(buffer);
18808            let mut peek_end = range.end;
18809            if range.end.row < buffer.max_row().0 {
18810                peek_end = Point::new(range.end.row + 1, 0);
18811            }
18812            buffer
18813                .diff_hunks_in_range(range.start..peek_end)
18814                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18815        })
18816    }
18817
18818    pub fn has_stageable_diff_hunks_in_ranges(
18819        &self,
18820        ranges: &[Range<Anchor>],
18821        snapshot: &MultiBufferSnapshot,
18822    ) -> bool {
18823        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18824        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18825    }
18826
18827    pub fn toggle_staged_selected_diff_hunks(
18828        &mut self,
18829        _: &::git::ToggleStaged,
18830        _: &mut Window,
18831        cx: &mut Context<Self>,
18832    ) {
18833        let snapshot = self.buffer.read(cx).snapshot(cx);
18834        let ranges: Vec<_> = self
18835            .selections
18836            .disjoint_anchors()
18837            .iter()
18838            .map(|s| s.range())
18839            .collect();
18840        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18841        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18842    }
18843
18844    pub fn set_render_diff_hunk_controls(
18845        &mut self,
18846        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18847        cx: &mut Context<Self>,
18848    ) {
18849        self.render_diff_hunk_controls = render_diff_hunk_controls;
18850        cx.notify();
18851    }
18852
18853    pub fn stage_and_next(
18854        &mut self,
18855        _: &::git::StageAndNext,
18856        window: &mut Window,
18857        cx: &mut Context<Self>,
18858    ) {
18859        self.do_stage_or_unstage_and_next(true, window, cx);
18860    }
18861
18862    pub fn unstage_and_next(
18863        &mut self,
18864        _: &::git::UnstageAndNext,
18865        window: &mut Window,
18866        cx: &mut Context<Self>,
18867    ) {
18868        self.do_stage_or_unstage_and_next(false, window, cx);
18869    }
18870
18871    pub fn stage_or_unstage_diff_hunks(
18872        &mut self,
18873        stage: bool,
18874        ranges: Vec<Range<Anchor>>,
18875        cx: &mut Context<Self>,
18876    ) {
18877        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18878        cx.spawn(async move |this, cx| {
18879            task.await?;
18880            this.update(cx, |this, cx| {
18881                let snapshot = this.buffer.read(cx).snapshot(cx);
18882                let chunk_by = this
18883                    .diff_hunks_in_ranges(&ranges, &snapshot)
18884                    .chunk_by(|hunk| hunk.buffer_id);
18885                for (buffer_id, hunks) in &chunk_by {
18886                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18887                }
18888            })
18889        })
18890        .detach_and_log_err(cx);
18891    }
18892
18893    fn save_buffers_for_ranges_if_needed(
18894        &mut self,
18895        ranges: &[Range<Anchor>],
18896        cx: &mut Context<Editor>,
18897    ) -> Task<Result<()>> {
18898        let multibuffer = self.buffer.read(cx);
18899        let snapshot = multibuffer.read(cx);
18900        let buffer_ids: HashSet<_> = ranges
18901            .iter()
18902            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18903            .collect();
18904        drop(snapshot);
18905
18906        let mut buffers = HashSet::default();
18907        for buffer_id in buffer_ids {
18908            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18909                let buffer = buffer_entity.read(cx);
18910                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18911                {
18912                    buffers.insert(buffer_entity);
18913                }
18914            }
18915        }
18916
18917        if let Some(project) = &self.project {
18918            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18919        } else {
18920            Task::ready(Ok(()))
18921        }
18922    }
18923
18924    fn do_stage_or_unstage_and_next(
18925        &mut self,
18926        stage: bool,
18927        window: &mut Window,
18928        cx: &mut Context<Self>,
18929    ) {
18930        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18931
18932        if ranges.iter().any(|range| range.start != range.end) {
18933            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18934            return;
18935        }
18936
18937        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18938        let snapshot = self.snapshot(window, cx);
18939        let position = self
18940            .selections
18941            .newest::<Point>(&snapshot.display_snapshot)
18942            .head();
18943        let mut row = snapshot
18944            .buffer_snapshot()
18945            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18946            .find(|hunk| hunk.row_range.start.0 > position.row)
18947            .map(|hunk| hunk.row_range.start);
18948
18949        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18950        // Outside of the project diff editor, wrap around to the beginning.
18951        if !all_diff_hunks_expanded {
18952            row = row.or_else(|| {
18953                snapshot
18954                    .buffer_snapshot()
18955                    .diff_hunks_in_range(Point::zero()..position)
18956                    .find(|hunk| hunk.row_range.end.0 < position.row)
18957                    .map(|hunk| hunk.row_range.start)
18958            });
18959        }
18960
18961        if let Some(row) = row {
18962            let destination = Point::new(row.0, 0);
18963            let autoscroll = Autoscroll::center();
18964
18965            self.unfold_ranges(&[destination..destination], false, false, cx);
18966            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18967                s.select_ranges([destination..destination]);
18968            });
18969        }
18970    }
18971
18972    fn do_stage_or_unstage(
18973        &self,
18974        stage: bool,
18975        buffer_id: BufferId,
18976        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18977        cx: &mut App,
18978    ) -> Option<()> {
18979        let project = self.project()?;
18980        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18981        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18982        let buffer_snapshot = buffer.read(cx).snapshot();
18983        let file_exists = buffer_snapshot
18984            .file()
18985            .is_some_and(|file| file.disk_state().exists());
18986        diff.update(cx, |diff, cx| {
18987            diff.stage_or_unstage_hunks(
18988                stage,
18989                &hunks
18990                    .map(|hunk| buffer_diff::DiffHunk {
18991                        buffer_range: hunk.buffer_range,
18992                        diff_base_byte_range: hunk.diff_base_byte_range,
18993                        secondary_status: hunk.secondary_status,
18994                        range: Point::zero()..Point::zero(), // unused
18995                    })
18996                    .collect::<Vec<_>>(),
18997                &buffer_snapshot,
18998                file_exists,
18999                cx,
19000            )
19001        });
19002        None
19003    }
19004
19005    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19006        let ranges: Vec<_> = self
19007            .selections
19008            .disjoint_anchors()
19009            .iter()
19010            .map(|s| s.range())
19011            .collect();
19012        self.buffer
19013            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19014    }
19015
19016    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19017        self.buffer.update(cx, |buffer, cx| {
19018            let ranges = vec![Anchor::min()..Anchor::max()];
19019            if !buffer.all_diff_hunks_expanded()
19020                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19021            {
19022                buffer.collapse_diff_hunks(ranges, cx);
19023                true
19024            } else {
19025                false
19026            }
19027        })
19028    }
19029
19030    fn toggle_diff_hunks_in_ranges(
19031        &mut self,
19032        ranges: Vec<Range<Anchor>>,
19033        cx: &mut Context<Editor>,
19034    ) {
19035        self.buffer.update(cx, |buffer, cx| {
19036            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19037            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19038        })
19039    }
19040
19041    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19042        self.buffer.update(cx, |buffer, cx| {
19043            let snapshot = buffer.snapshot(cx);
19044            let excerpt_id = range.end.excerpt_id;
19045            let point_range = range.to_point(&snapshot);
19046            let expand = !buffer.single_hunk_is_expanded(range, cx);
19047            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19048        })
19049    }
19050
19051    pub(crate) fn apply_all_diff_hunks(
19052        &mut self,
19053        _: &ApplyAllDiffHunks,
19054        window: &mut Window,
19055        cx: &mut Context<Self>,
19056    ) {
19057        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19058
19059        let buffers = self.buffer.read(cx).all_buffers();
19060        for branch_buffer in buffers {
19061            branch_buffer.update(cx, |branch_buffer, cx| {
19062                branch_buffer.merge_into_base(Vec::new(), cx);
19063            });
19064        }
19065
19066        if let Some(project) = self.project.clone() {
19067            self.save(
19068                SaveOptions {
19069                    format: true,
19070                    autosave: false,
19071                },
19072                project,
19073                window,
19074                cx,
19075            )
19076            .detach_and_log_err(cx);
19077        }
19078    }
19079
19080    pub(crate) fn apply_selected_diff_hunks(
19081        &mut self,
19082        _: &ApplyDiffHunk,
19083        window: &mut Window,
19084        cx: &mut Context<Self>,
19085    ) {
19086        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19087        let snapshot = self.snapshot(window, cx);
19088        let hunks = snapshot.hunks_for_ranges(
19089            self.selections
19090                .all(&snapshot.display_snapshot)
19091                .into_iter()
19092                .map(|selection| selection.range()),
19093        );
19094        let mut ranges_by_buffer = HashMap::default();
19095        self.transact(window, cx, |editor, _window, cx| {
19096            for hunk in hunks {
19097                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19098                    ranges_by_buffer
19099                        .entry(buffer.clone())
19100                        .or_insert_with(Vec::new)
19101                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19102                }
19103            }
19104
19105            for (buffer, ranges) in ranges_by_buffer {
19106                buffer.update(cx, |buffer, cx| {
19107                    buffer.merge_into_base(ranges, cx);
19108                });
19109            }
19110        });
19111
19112        if let Some(project) = self.project.clone() {
19113            self.save(
19114                SaveOptions {
19115                    format: true,
19116                    autosave: false,
19117                },
19118                project,
19119                window,
19120                cx,
19121            )
19122            .detach_and_log_err(cx);
19123        }
19124    }
19125
19126    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19127        if hovered != self.gutter_hovered {
19128            self.gutter_hovered = hovered;
19129            cx.notify();
19130        }
19131    }
19132
19133    pub fn insert_blocks(
19134        &mut self,
19135        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19136        autoscroll: Option<Autoscroll>,
19137        cx: &mut Context<Self>,
19138    ) -> Vec<CustomBlockId> {
19139        let blocks = self
19140            .display_map
19141            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19142        if let Some(autoscroll) = autoscroll {
19143            self.request_autoscroll(autoscroll, cx);
19144        }
19145        cx.notify();
19146        blocks
19147    }
19148
19149    pub fn resize_blocks(
19150        &mut self,
19151        heights: HashMap<CustomBlockId, u32>,
19152        autoscroll: Option<Autoscroll>,
19153        cx: &mut Context<Self>,
19154    ) {
19155        self.display_map
19156            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19157        if let Some(autoscroll) = autoscroll {
19158            self.request_autoscroll(autoscroll, cx);
19159        }
19160        cx.notify();
19161    }
19162
19163    pub fn replace_blocks(
19164        &mut self,
19165        renderers: HashMap<CustomBlockId, RenderBlock>,
19166        autoscroll: Option<Autoscroll>,
19167        cx: &mut Context<Self>,
19168    ) {
19169        self.display_map
19170            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19171        if let Some(autoscroll) = autoscroll {
19172            self.request_autoscroll(autoscroll, cx);
19173        }
19174        cx.notify();
19175    }
19176
19177    pub fn remove_blocks(
19178        &mut self,
19179        block_ids: HashSet<CustomBlockId>,
19180        autoscroll: Option<Autoscroll>,
19181        cx: &mut Context<Self>,
19182    ) {
19183        self.display_map.update(cx, |display_map, cx| {
19184            display_map.remove_blocks(block_ids, cx)
19185        });
19186        if let Some(autoscroll) = autoscroll {
19187            self.request_autoscroll(autoscroll, cx);
19188        }
19189        cx.notify();
19190    }
19191
19192    pub fn row_for_block(
19193        &self,
19194        block_id: CustomBlockId,
19195        cx: &mut Context<Self>,
19196    ) -> Option<DisplayRow> {
19197        self.display_map
19198            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19199    }
19200
19201    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19202        self.focused_block = Some(focused_block);
19203    }
19204
19205    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19206        self.focused_block.take()
19207    }
19208
19209    pub fn insert_creases(
19210        &mut self,
19211        creases: impl IntoIterator<Item = Crease<Anchor>>,
19212        cx: &mut Context<Self>,
19213    ) -> Vec<CreaseId> {
19214        self.display_map
19215            .update(cx, |map, cx| map.insert_creases(creases, cx))
19216    }
19217
19218    pub fn remove_creases(
19219        &mut self,
19220        ids: impl IntoIterator<Item = CreaseId>,
19221        cx: &mut Context<Self>,
19222    ) -> Vec<(CreaseId, Range<Anchor>)> {
19223        self.display_map
19224            .update(cx, |map, cx| map.remove_creases(ids, cx))
19225    }
19226
19227    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19228        self.display_map
19229            .update(cx, |map, cx| map.snapshot(cx))
19230            .longest_row()
19231    }
19232
19233    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19234        self.display_map
19235            .update(cx, |map, cx| map.snapshot(cx))
19236            .max_point()
19237    }
19238
19239    pub fn text(&self, cx: &App) -> String {
19240        self.buffer.read(cx).read(cx).text()
19241    }
19242
19243    pub fn is_empty(&self, cx: &App) -> bool {
19244        self.buffer.read(cx).read(cx).is_empty()
19245    }
19246
19247    pub fn text_option(&self, cx: &App) -> Option<String> {
19248        let text = self.text(cx);
19249        let text = text.trim();
19250
19251        if text.is_empty() {
19252            return None;
19253        }
19254
19255        Some(text.to_string())
19256    }
19257
19258    pub fn set_text(
19259        &mut self,
19260        text: impl Into<Arc<str>>,
19261        window: &mut Window,
19262        cx: &mut Context<Self>,
19263    ) {
19264        self.transact(window, cx, |this, _, cx| {
19265            this.buffer
19266                .read(cx)
19267                .as_singleton()
19268                .expect("you can only call set_text on editors for singleton buffers")
19269                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19270        });
19271    }
19272
19273    pub fn display_text(&self, cx: &mut App) -> String {
19274        self.display_map
19275            .update(cx, |map, cx| map.snapshot(cx))
19276            .text()
19277    }
19278
19279    fn create_minimap(
19280        &self,
19281        minimap_settings: MinimapSettings,
19282        window: &mut Window,
19283        cx: &mut Context<Self>,
19284    ) -> Option<Entity<Self>> {
19285        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19286            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19287    }
19288
19289    fn initialize_new_minimap(
19290        &self,
19291        minimap_settings: MinimapSettings,
19292        window: &mut Window,
19293        cx: &mut Context<Self>,
19294    ) -> Entity<Self> {
19295        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19296
19297        let mut minimap = Editor::new_internal(
19298            EditorMode::Minimap {
19299                parent: cx.weak_entity(),
19300            },
19301            self.buffer.clone(),
19302            None,
19303            Some(self.display_map.clone()),
19304            window,
19305            cx,
19306        );
19307        minimap.scroll_manager.clone_state(&self.scroll_manager);
19308        minimap.set_text_style_refinement(TextStyleRefinement {
19309            font_size: Some(MINIMAP_FONT_SIZE),
19310            font_weight: Some(MINIMAP_FONT_WEIGHT),
19311            ..Default::default()
19312        });
19313        minimap.update_minimap_configuration(minimap_settings, cx);
19314        cx.new(|_| minimap)
19315    }
19316
19317    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19318        let current_line_highlight = minimap_settings
19319            .current_line_highlight
19320            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19321        self.set_current_line_highlight(Some(current_line_highlight));
19322    }
19323
19324    pub fn minimap(&self) -> Option<&Entity<Self>> {
19325        self.minimap
19326            .as_ref()
19327            .filter(|_| self.minimap_visibility.visible())
19328    }
19329
19330    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19331        let mut wrap_guides = smallvec![];
19332
19333        if self.show_wrap_guides == Some(false) {
19334            return wrap_guides;
19335        }
19336
19337        let settings = self.buffer.read(cx).language_settings(cx);
19338        if settings.show_wrap_guides {
19339            match self.soft_wrap_mode(cx) {
19340                SoftWrap::Column(soft_wrap) => {
19341                    wrap_guides.push((soft_wrap as usize, true));
19342                }
19343                SoftWrap::Bounded(soft_wrap) => {
19344                    wrap_guides.push((soft_wrap as usize, true));
19345                }
19346                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19347            }
19348            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19349        }
19350
19351        wrap_guides
19352    }
19353
19354    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19355        let settings = self.buffer.read(cx).language_settings(cx);
19356        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19357        match mode {
19358            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19359                SoftWrap::None
19360            }
19361            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19362            language_settings::SoftWrap::PreferredLineLength => {
19363                SoftWrap::Column(settings.preferred_line_length)
19364            }
19365            language_settings::SoftWrap::Bounded => {
19366                SoftWrap::Bounded(settings.preferred_line_length)
19367            }
19368        }
19369    }
19370
19371    pub fn set_soft_wrap_mode(
19372        &mut self,
19373        mode: language_settings::SoftWrap,
19374
19375        cx: &mut Context<Self>,
19376    ) {
19377        self.soft_wrap_mode_override = Some(mode);
19378        cx.notify();
19379    }
19380
19381    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19382        self.hard_wrap = hard_wrap;
19383        cx.notify();
19384    }
19385
19386    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19387        self.text_style_refinement = Some(style);
19388    }
19389
19390    /// called by the Element so we know what style we were most recently rendered with.
19391    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19392        // We intentionally do not inform the display map about the minimap style
19393        // so that wrapping is not recalculated and stays consistent for the editor
19394        // and its linked minimap.
19395        if !self.mode.is_minimap() {
19396            let font = style.text.font();
19397            let font_size = style.text.font_size.to_pixels(window.rem_size());
19398            let display_map = self
19399                .placeholder_display_map
19400                .as_ref()
19401                .filter(|_| self.is_empty(cx))
19402                .unwrap_or(&self.display_map);
19403
19404            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19405        }
19406        self.style = Some(style);
19407    }
19408
19409    pub fn style(&self) -> Option<&EditorStyle> {
19410        self.style.as_ref()
19411    }
19412
19413    // Called by the element. This method is not designed to be called outside of the editor
19414    // element's layout code because it does not notify when rewrapping is computed synchronously.
19415    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19416        if self.is_empty(cx) {
19417            self.placeholder_display_map
19418                .as_ref()
19419                .map_or(false, |display_map| {
19420                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19421                })
19422        } else {
19423            self.display_map
19424                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19425        }
19426    }
19427
19428    pub fn set_soft_wrap(&mut self) {
19429        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19430    }
19431
19432    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19433        if self.soft_wrap_mode_override.is_some() {
19434            self.soft_wrap_mode_override.take();
19435        } else {
19436            let soft_wrap = match self.soft_wrap_mode(cx) {
19437                SoftWrap::GitDiff => return,
19438                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19439                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19440                    language_settings::SoftWrap::None
19441                }
19442            };
19443            self.soft_wrap_mode_override = Some(soft_wrap);
19444        }
19445        cx.notify();
19446    }
19447
19448    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19449        let Some(workspace) = self.workspace() else {
19450            return;
19451        };
19452        let fs = workspace.read(cx).app_state().fs.clone();
19453        let current_show = TabBarSettings::get_global(cx).show;
19454        update_settings_file(fs, cx, move |setting, _| {
19455            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19456        });
19457    }
19458
19459    pub fn toggle_indent_guides(
19460        &mut self,
19461        _: &ToggleIndentGuides,
19462        _: &mut Window,
19463        cx: &mut Context<Self>,
19464    ) {
19465        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19466            self.buffer
19467                .read(cx)
19468                .language_settings(cx)
19469                .indent_guides
19470                .enabled
19471        });
19472        self.show_indent_guides = Some(!currently_enabled);
19473        cx.notify();
19474    }
19475
19476    fn should_show_indent_guides(&self) -> Option<bool> {
19477        self.show_indent_guides
19478    }
19479
19480    pub fn toggle_line_numbers(
19481        &mut self,
19482        _: &ToggleLineNumbers,
19483        _: &mut Window,
19484        cx: &mut Context<Self>,
19485    ) {
19486        let mut editor_settings = EditorSettings::get_global(cx).clone();
19487        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19488        EditorSettings::override_global(editor_settings, cx);
19489    }
19490
19491    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19492        if let Some(show_line_numbers) = self.show_line_numbers {
19493            return show_line_numbers;
19494        }
19495        EditorSettings::get_global(cx).gutter.line_numbers
19496    }
19497
19498    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19499        self.use_relative_line_numbers
19500            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19501    }
19502
19503    pub fn toggle_relative_line_numbers(
19504        &mut self,
19505        _: &ToggleRelativeLineNumbers,
19506        _: &mut Window,
19507        cx: &mut Context<Self>,
19508    ) {
19509        let is_relative = self.should_use_relative_line_numbers(cx);
19510        self.set_relative_line_number(Some(!is_relative), cx)
19511    }
19512
19513    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19514        self.use_relative_line_numbers = is_relative;
19515        cx.notify();
19516    }
19517
19518    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19519        self.show_gutter = show_gutter;
19520        cx.notify();
19521    }
19522
19523    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19524        self.show_scrollbars = ScrollbarAxes {
19525            horizontal: show,
19526            vertical: show,
19527        };
19528        cx.notify();
19529    }
19530
19531    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19532        self.show_scrollbars.vertical = show;
19533        cx.notify();
19534    }
19535
19536    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19537        self.show_scrollbars.horizontal = show;
19538        cx.notify();
19539    }
19540
19541    pub fn set_minimap_visibility(
19542        &mut self,
19543        minimap_visibility: MinimapVisibility,
19544        window: &mut Window,
19545        cx: &mut Context<Self>,
19546    ) {
19547        if self.minimap_visibility != minimap_visibility {
19548            if minimap_visibility.visible() && self.minimap.is_none() {
19549                let minimap_settings = EditorSettings::get_global(cx).minimap;
19550                self.minimap =
19551                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19552            }
19553            self.minimap_visibility = minimap_visibility;
19554            cx.notify();
19555        }
19556    }
19557
19558    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19559        self.set_show_scrollbars(false, cx);
19560        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19561    }
19562
19563    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19564        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19565    }
19566
19567    /// Normally the text in full mode and auto height editors is padded on the
19568    /// left side by roughly half a character width for improved hit testing.
19569    ///
19570    /// Use this method to disable this for cases where this is not wanted (e.g.
19571    /// if you want to align the editor text with some other text above or below)
19572    /// or if you want to add this padding to single-line editors.
19573    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19574        self.offset_content = offset_content;
19575        cx.notify();
19576    }
19577
19578    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19579        self.show_line_numbers = Some(show_line_numbers);
19580        cx.notify();
19581    }
19582
19583    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19584        self.disable_expand_excerpt_buttons = true;
19585        cx.notify();
19586    }
19587
19588    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19589        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19590        cx.notify();
19591    }
19592
19593    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19594        self.show_code_actions = Some(show_code_actions);
19595        cx.notify();
19596    }
19597
19598    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19599        self.show_runnables = Some(show_runnables);
19600        cx.notify();
19601    }
19602
19603    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19604        self.show_breakpoints = Some(show_breakpoints);
19605        cx.notify();
19606    }
19607
19608    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19609        if self.display_map.read(cx).masked != masked {
19610            self.display_map.update(cx, |map, _| map.masked = masked);
19611        }
19612        cx.notify()
19613    }
19614
19615    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19616        self.show_wrap_guides = Some(show_wrap_guides);
19617        cx.notify();
19618    }
19619
19620    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19621        self.show_indent_guides = Some(show_indent_guides);
19622        cx.notify();
19623    }
19624
19625    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19626        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19627            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19628                && let Some(dir) = file.abs_path(cx).parent()
19629            {
19630                return Some(dir.to_owned());
19631            }
19632        }
19633
19634        None
19635    }
19636
19637    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19638        self.active_excerpt(cx)?
19639            .1
19640            .read(cx)
19641            .file()
19642            .and_then(|f| f.as_local())
19643    }
19644
19645    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19646        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19647            let buffer = buffer.read(cx);
19648            if let Some(project_path) = buffer.project_path(cx) {
19649                let project = self.project()?.read(cx);
19650                project.absolute_path(&project_path, cx)
19651            } else {
19652                buffer
19653                    .file()
19654                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19655            }
19656        })
19657    }
19658
19659    pub fn reveal_in_finder(
19660        &mut self,
19661        _: &RevealInFileManager,
19662        _window: &mut Window,
19663        cx: &mut Context<Self>,
19664    ) {
19665        if let Some(target) = self.target_file(cx) {
19666            cx.reveal_path(&target.abs_path(cx));
19667        }
19668    }
19669
19670    pub fn copy_path(
19671        &mut self,
19672        _: &zed_actions::workspace::CopyPath,
19673        _window: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        if let Some(path) = self.target_file_abs_path(cx)
19677            && let Some(path) = path.to_str()
19678        {
19679            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19680        } else {
19681            cx.propagate();
19682        }
19683    }
19684
19685    pub fn copy_relative_path(
19686        &mut self,
19687        _: &zed_actions::workspace::CopyRelativePath,
19688        _window: &mut Window,
19689        cx: &mut Context<Self>,
19690    ) {
19691        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19692            let project = self.project()?.read(cx);
19693            let path = buffer.read(cx).file()?.path();
19694            let path = path.display(project.path_style(cx));
19695            Some(path)
19696        }) {
19697            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19698        } else {
19699            cx.propagate();
19700        }
19701    }
19702
19703    /// Returns the project path for the editor's buffer, if any buffer is
19704    /// opened in the editor.
19705    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19706        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19707            buffer.read(cx).project_path(cx)
19708        } else {
19709            None
19710        }
19711    }
19712
19713    // Returns true if the editor handled a go-to-line request
19714    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19715        maybe!({
19716            let breakpoint_store = self.breakpoint_store.as_ref()?;
19717
19718            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19719            else {
19720                self.clear_row_highlights::<ActiveDebugLine>();
19721                return None;
19722            };
19723
19724            let position = active_stack_frame.position;
19725            let buffer_id = position.buffer_id?;
19726            let snapshot = self
19727                .project
19728                .as_ref()?
19729                .read(cx)
19730                .buffer_for_id(buffer_id, cx)?
19731                .read(cx)
19732                .snapshot();
19733
19734            let mut handled = false;
19735            for (id, ExcerptRange { context, .. }) in
19736                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19737            {
19738                if context.start.cmp(&position, &snapshot).is_ge()
19739                    || context.end.cmp(&position, &snapshot).is_lt()
19740                {
19741                    continue;
19742                }
19743                let snapshot = self.buffer.read(cx).snapshot(cx);
19744                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19745
19746                handled = true;
19747                self.clear_row_highlights::<ActiveDebugLine>();
19748
19749                self.go_to_line::<ActiveDebugLine>(
19750                    multibuffer_anchor,
19751                    Some(cx.theme().colors().editor_debugger_active_line_background),
19752                    window,
19753                    cx,
19754                );
19755
19756                cx.notify();
19757            }
19758
19759            handled.then_some(())
19760        })
19761        .is_some()
19762    }
19763
19764    pub fn copy_file_name_without_extension(
19765        &mut self,
19766        _: &CopyFileNameWithoutExtension,
19767        _: &mut Window,
19768        cx: &mut Context<Self>,
19769    ) {
19770        if let Some(file) = self.target_file(cx)
19771            && let Some(file_stem) = file.path().file_stem()
19772        {
19773            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19774        }
19775    }
19776
19777    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19778        if let Some(file) = self.target_file(cx)
19779            && let Some(name) = file.path().file_name()
19780        {
19781            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19782        }
19783    }
19784
19785    pub fn toggle_git_blame(
19786        &mut self,
19787        _: &::git::Blame,
19788        window: &mut Window,
19789        cx: &mut Context<Self>,
19790    ) {
19791        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19792
19793        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19794            self.start_git_blame(true, window, cx);
19795        }
19796
19797        cx.notify();
19798    }
19799
19800    pub fn toggle_git_blame_inline(
19801        &mut self,
19802        _: &ToggleGitBlameInline,
19803        window: &mut Window,
19804        cx: &mut Context<Self>,
19805    ) {
19806        self.toggle_git_blame_inline_internal(true, window, cx);
19807        cx.notify();
19808    }
19809
19810    pub fn open_git_blame_commit(
19811        &mut self,
19812        _: &OpenGitBlameCommit,
19813        window: &mut Window,
19814        cx: &mut Context<Self>,
19815    ) {
19816        self.open_git_blame_commit_internal(window, cx);
19817    }
19818
19819    fn open_git_blame_commit_internal(
19820        &mut self,
19821        window: &mut Window,
19822        cx: &mut Context<Self>,
19823    ) -> Option<()> {
19824        let blame = self.blame.as_ref()?;
19825        let snapshot = self.snapshot(window, cx);
19826        let cursor = self
19827            .selections
19828            .newest::<Point>(&snapshot.display_snapshot)
19829            .head();
19830        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19831        let (_, blame_entry) = blame
19832            .update(cx, |blame, cx| {
19833                blame
19834                    .blame_for_rows(
19835                        &[RowInfo {
19836                            buffer_id: Some(buffer.remote_id()),
19837                            buffer_row: Some(point.row),
19838                            ..Default::default()
19839                        }],
19840                        cx,
19841                    )
19842                    .next()
19843            })
19844            .flatten()?;
19845        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19846        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19847        let workspace = self.workspace()?.downgrade();
19848        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19849        None
19850    }
19851
19852    pub fn git_blame_inline_enabled(&self) -> bool {
19853        self.git_blame_inline_enabled
19854    }
19855
19856    pub fn toggle_selection_menu(
19857        &mut self,
19858        _: &ToggleSelectionMenu,
19859        _: &mut Window,
19860        cx: &mut Context<Self>,
19861    ) {
19862        self.show_selection_menu = self
19863            .show_selection_menu
19864            .map(|show_selections_menu| !show_selections_menu)
19865            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19866
19867        cx.notify();
19868    }
19869
19870    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19871        self.show_selection_menu
19872            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19873    }
19874
19875    fn start_git_blame(
19876        &mut self,
19877        user_triggered: bool,
19878        window: &mut Window,
19879        cx: &mut Context<Self>,
19880    ) {
19881        if let Some(project) = self.project() {
19882            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19883                && buffer.read(cx).file().is_none()
19884            {
19885                return;
19886            }
19887
19888            let focused = self.focus_handle(cx).contains_focused(window, cx);
19889
19890            let project = project.clone();
19891            let blame = cx
19892                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19893            self.blame_subscription =
19894                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19895            self.blame = Some(blame);
19896        }
19897    }
19898
19899    fn toggle_git_blame_inline_internal(
19900        &mut self,
19901        user_triggered: bool,
19902        window: &mut Window,
19903        cx: &mut Context<Self>,
19904    ) {
19905        if self.git_blame_inline_enabled {
19906            self.git_blame_inline_enabled = false;
19907            self.show_git_blame_inline = false;
19908            self.show_git_blame_inline_delay_task.take();
19909        } else {
19910            self.git_blame_inline_enabled = true;
19911            self.start_git_blame_inline(user_triggered, window, cx);
19912        }
19913
19914        cx.notify();
19915    }
19916
19917    fn start_git_blame_inline(
19918        &mut self,
19919        user_triggered: bool,
19920        window: &mut Window,
19921        cx: &mut Context<Self>,
19922    ) {
19923        self.start_git_blame(user_triggered, window, cx);
19924
19925        if ProjectSettings::get_global(cx)
19926            .git
19927            .inline_blame_delay()
19928            .is_some()
19929        {
19930            self.start_inline_blame_timer(window, cx);
19931        } else {
19932            self.show_git_blame_inline = true
19933        }
19934    }
19935
19936    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19937        self.blame.as_ref()
19938    }
19939
19940    pub fn show_git_blame_gutter(&self) -> bool {
19941        self.show_git_blame_gutter
19942    }
19943
19944    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19945        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19946    }
19947
19948    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19949        self.show_git_blame_inline
19950            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19951            && !self.newest_selection_head_on_empty_line(cx)
19952            && self.has_blame_entries(cx)
19953    }
19954
19955    fn has_blame_entries(&self, cx: &App) -> bool {
19956        self.blame()
19957            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19958    }
19959
19960    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19961        let cursor_anchor = self.selections.newest_anchor().head();
19962
19963        let snapshot = self.buffer.read(cx).snapshot(cx);
19964        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19965
19966        snapshot.line_len(buffer_row) == 0
19967    }
19968
19969    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19970        let buffer_and_selection = maybe!({
19971            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19972            let selection_range = selection.range();
19973
19974            let multi_buffer = self.buffer().read(cx);
19975            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19976            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19977
19978            let (buffer, range, _) = if selection.reversed {
19979                buffer_ranges.first()
19980            } else {
19981                buffer_ranges.last()
19982            }?;
19983
19984            let selection = text::ToPoint::to_point(&range.start, buffer).row
19985                ..text::ToPoint::to_point(&range.end, buffer).row;
19986            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19987        });
19988
19989        let Some((buffer, selection)) = buffer_and_selection else {
19990            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19991        };
19992
19993        let Some(project) = self.project() else {
19994            return Task::ready(Err(anyhow!("editor does not have project")));
19995        };
19996
19997        project.update(cx, |project, cx| {
19998            project.get_permalink_to_line(&buffer, selection, cx)
19999        })
20000    }
20001
20002    pub fn copy_permalink_to_line(
20003        &mut self,
20004        _: &CopyPermalinkToLine,
20005        window: &mut Window,
20006        cx: &mut Context<Self>,
20007    ) {
20008        let permalink_task = self.get_permalink_to_line(cx);
20009        let workspace = self.workspace();
20010
20011        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20012            Ok(permalink) => {
20013                cx.update(|_, cx| {
20014                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20015                })
20016                .ok();
20017            }
20018            Err(err) => {
20019                let message = format!("Failed to copy permalink: {err}");
20020
20021                anyhow::Result::<()>::Err(err).log_err();
20022
20023                if let Some(workspace) = workspace {
20024                    workspace
20025                        .update_in(cx, |workspace, _, cx| {
20026                            struct CopyPermalinkToLine;
20027
20028                            workspace.show_toast(
20029                                Toast::new(
20030                                    NotificationId::unique::<CopyPermalinkToLine>(),
20031                                    message,
20032                                ),
20033                                cx,
20034                            )
20035                        })
20036                        .ok();
20037                }
20038            }
20039        })
20040        .detach();
20041    }
20042
20043    pub fn copy_file_location(
20044        &mut self,
20045        _: &CopyFileLocation,
20046        _: &mut Window,
20047        cx: &mut Context<Self>,
20048    ) {
20049        let selection = self
20050            .selections
20051            .newest::<Point>(&self.display_snapshot(cx))
20052            .start
20053            .row
20054            + 1;
20055        if let Some(file) = self.target_file(cx) {
20056            let path = file.path().display(file.path_style(cx));
20057            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20058        }
20059    }
20060
20061    pub fn open_permalink_to_line(
20062        &mut self,
20063        _: &OpenPermalinkToLine,
20064        window: &mut Window,
20065        cx: &mut Context<Self>,
20066    ) {
20067        let permalink_task = self.get_permalink_to_line(cx);
20068        let workspace = self.workspace();
20069
20070        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20071            Ok(permalink) => {
20072                cx.update(|_, cx| {
20073                    cx.open_url(permalink.as_ref());
20074                })
20075                .ok();
20076            }
20077            Err(err) => {
20078                let message = format!("Failed to open permalink: {err}");
20079
20080                anyhow::Result::<()>::Err(err).log_err();
20081
20082                if let Some(workspace) = workspace {
20083                    workspace
20084                        .update(cx, |workspace, cx| {
20085                            struct OpenPermalinkToLine;
20086
20087                            workspace.show_toast(
20088                                Toast::new(
20089                                    NotificationId::unique::<OpenPermalinkToLine>(),
20090                                    message,
20091                                ),
20092                                cx,
20093                            )
20094                        })
20095                        .ok();
20096                }
20097            }
20098        })
20099        .detach();
20100    }
20101
20102    pub fn insert_uuid_v4(
20103        &mut self,
20104        _: &InsertUuidV4,
20105        window: &mut Window,
20106        cx: &mut Context<Self>,
20107    ) {
20108        self.insert_uuid(UuidVersion::V4, window, cx);
20109    }
20110
20111    pub fn insert_uuid_v7(
20112        &mut self,
20113        _: &InsertUuidV7,
20114        window: &mut Window,
20115        cx: &mut Context<Self>,
20116    ) {
20117        self.insert_uuid(UuidVersion::V7, window, cx);
20118    }
20119
20120    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20122        self.transact(window, cx, |this, window, cx| {
20123            let edits = this
20124                .selections
20125                .all::<Point>(&this.display_snapshot(cx))
20126                .into_iter()
20127                .map(|selection| {
20128                    let uuid = match version {
20129                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20130                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20131                    };
20132
20133                    (selection.range(), uuid.to_string())
20134                });
20135            this.edit(edits, cx);
20136            this.refresh_edit_prediction(true, false, window, cx);
20137        });
20138    }
20139
20140    pub fn open_selections_in_multibuffer(
20141        &mut self,
20142        _: &OpenSelectionsInMultibuffer,
20143        window: &mut Window,
20144        cx: &mut Context<Self>,
20145    ) {
20146        let multibuffer = self.buffer.read(cx);
20147
20148        let Some(buffer) = multibuffer.as_singleton() else {
20149            return;
20150        };
20151
20152        let Some(workspace) = self.workspace() else {
20153            return;
20154        };
20155
20156        let title = multibuffer.title(cx).to_string();
20157
20158        let locations = self
20159            .selections
20160            .all_anchors(cx)
20161            .iter()
20162            .map(|selection| {
20163                (
20164                    buffer.clone(),
20165                    (selection.start.text_anchor..selection.end.text_anchor)
20166                        .to_point(buffer.read(cx)),
20167                )
20168            })
20169            .into_group_map();
20170
20171        cx.spawn_in(window, async move |_, cx| {
20172            workspace.update_in(cx, |workspace, window, cx| {
20173                Self::open_locations_in_multibuffer(
20174                    workspace,
20175                    locations,
20176                    format!("Selections for '{title}'"),
20177                    false,
20178                    MultibufferSelectionMode::All,
20179                    window,
20180                    cx,
20181                );
20182            })
20183        })
20184        .detach();
20185    }
20186
20187    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20188    /// last highlight added will be used.
20189    ///
20190    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20191    pub fn highlight_rows<T: 'static>(
20192        &mut self,
20193        range: Range<Anchor>,
20194        color: Hsla,
20195        options: RowHighlightOptions,
20196        cx: &mut Context<Self>,
20197    ) {
20198        let snapshot = self.buffer().read(cx).snapshot(cx);
20199        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20200        let ix = row_highlights.binary_search_by(|highlight| {
20201            Ordering::Equal
20202                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20203                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20204        });
20205
20206        if let Err(mut ix) = ix {
20207            let index = post_inc(&mut self.highlight_order);
20208
20209            // If this range intersects with the preceding highlight, then merge it with
20210            // the preceding highlight. Otherwise insert a new highlight.
20211            let mut merged = false;
20212            if ix > 0 {
20213                let prev_highlight = &mut row_highlights[ix - 1];
20214                if prev_highlight
20215                    .range
20216                    .end
20217                    .cmp(&range.start, &snapshot)
20218                    .is_ge()
20219                {
20220                    ix -= 1;
20221                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20222                        prev_highlight.range.end = range.end;
20223                    }
20224                    merged = true;
20225                    prev_highlight.index = index;
20226                    prev_highlight.color = color;
20227                    prev_highlight.options = options;
20228                }
20229            }
20230
20231            if !merged {
20232                row_highlights.insert(
20233                    ix,
20234                    RowHighlight {
20235                        range,
20236                        index,
20237                        color,
20238                        options,
20239                        type_id: TypeId::of::<T>(),
20240                    },
20241                );
20242            }
20243
20244            // If any of the following highlights intersect with this one, merge them.
20245            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20246                let highlight = &row_highlights[ix];
20247                if next_highlight
20248                    .range
20249                    .start
20250                    .cmp(&highlight.range.end, &snapshot)
20251                    .is_le()
20252                {
20253                    if next_highlight
20254                        .range
20255                        .end
20256                        .cmp(&highlight.range.end, &snapshot)
20257                        .is_gt()
20258                    {
20259                        row_highlights[ix].range.end = next_highlight.range.end;
20260                    }
20261                    row_highlights.remove(ix + 1);
20262                } else {
20263                    break;
20264                }
20265            }
20266        }
20267    }
20268
20269    /// Remove any highlighted row ranges of the given type that intersect the
20270    /// given ranges.
20271    pub fn remove_highlighted_rows<T: 'static>(
20272        &mut self,
20273        ranges_to_remove: Vec<Range<Anchor>>,
20274        cx: &mut Context<Self>,
20275    ) {
20276        let snapshot = self.buffer().read(cx).snapshot(cx);
20277        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20278        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20279        row_highlights.retain(|highlight| {
20280            while let Some(range_to_remove) = ranges_to_remove.peek() {
20281                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20282                    Ordering::Less | Ordering::Equal => {
20283                        ranges_to_remove.next();
20284                    }
20285                    Ordering::Greater => {
20286                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20287                            Ordering::Less | Ordering::Equal => {
20288                                return false;
20289                            }
20290                            Ordering::Greater => break,
20291                        }
20292                    }
20293                }
20294            }
20295
20296            true
20297        })
20298    }
20299
20300    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20301    pub fn clear_row_highlights<T: 'static>(&mut self) {
20302        self.highlighted_rows.remove(&TypeId::of::<T>());
20303    }
20304
20305    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20306    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20307        self.highlighted_rows
20308            .get(&TypeId::of::<T>())
20309            .map_or(&[] as &[_], |vec| vec.as_slice())
20310            .iter()
20311            .map(|highlight| (highlight.range.clone(), highlight.color))
20312    }
20313
20314    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20315    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20316    /// Allows to ignore certain kinds of highlights.
20317    pub fn highlighted_display_rows(
20318        &self,
20319        window: &mut Window,
20320        cx: &mut App,
20321    ) -> BTreeMap<DisplayRow, LineHighlight> {
20322        let snapshot = self.snapshot(window, cx);
20323        let mut used_highlight_orders = HashMap::default();
20324        self.highlighted_rows
20325            .iter()
20326            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20327            .fold(
20328                BTreeMap::<DisplayRow, LineHighlight>::new(),
20329                |mut unique_rows, highlight| {
20330                    let start = highlight.range.start.to_display_point(&snapshot);
20331                    let end = highlight.range.end.to_display_point(&snapshot);
20332                    let start_row = start.row().0;
20333                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20334                        && end.column() == 0
20335                    {
20336                        end.row().0.saturating_sub(1)
20337                    } else {
20338                        end.row().0
20339                    };
20340                    for row in start_row..=end_row {
20341                        let used_index =
20342                            used_highlight_orders.entry(row).or_insert(highlight.index);
20343                        if highlight.index >= *used_index {
20344                            *used_index = highlight.index;
20345                            unique_rows.insert(
20346                                DisplayRow(row),
20347                                LineHighlight {
20348                                    include_gutter: highlight.options.include_gutter,
20349                                    border: None,
20350                                    background: highlight.color.into(),
20351                                    type_id: Some(highlight.type_id),
20352                                },
20353                            );
20354                        }
20355                    }
20356                    unique_rows
20357                },
20358            )
20359    }
20360
20361    pub fn highlighted_display_row_for_autoscroll(
20362        &self,
20363        snapshot: &DisplaySnapshot,
20364    ) -> Option<DisplayRow> {
20365        self.highlighted_rows
20366            .values()
20367            .flat_map(|highlighted_rows| highlighted_rows.iter())
20368            .filter_map(|highlight| {
20369                if highlight.options.autoscroll {
20370                    Some(highlight.range.start.to_display_point(snapshot).row())
20371                } else {
20372                    None
20373                }
20374            })
20375            .min()
20376    }
20377
20378    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20379        self.highlight_background::<SearchWithinRange>(
20380            ranges,
20381            |colors| colors.colors().editor_document_highlight_read_background,
20382            cx,
20383        )
20384    }
20385
20386    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20387        self.breadcrumb_header = Some(new_header);
20388    }
20389
20390    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20391        self.clear_background_highlights::<SearchWithinRange>(cx);
20392    }
20393
20394    pub fn highlight_background<T: 'static>(
20395        &mut self,
20396        ranges: &[Range<Anchor>],
20397        color_fetcher: fn(&Theme) -> Hsla,
20398        cx: &mut Context<Self>,
20399    ) {
20400        self.background_highlights.insert(
20401            HighlightKey::Type(TypeId::of::<T>()),
20402            (color_fetcher, Arc::from(ranges)),
20403        );
20404        self.scrollbar_marker_state.dirty = true;
20405        cx.notify();
20406    }
20407
20408    pub fn highlight_background_key<T: 'static>(
20409        &mut self,
20410        key: usize,
20411        ranges: &[Range<Anchor>],
20412        color_fetcher: fn(&Theme) -> Hsla,
20413        cx: &mut Context<Self>,
20414    ) {
20415        self.background_highlights.insert(
20416            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20417            (color_fetcher, Arc::from(ranges)),
20418        );
20419        self.scrollbar_marker_state.dirty = true;
20420        cx.notify();
20421    }
20422
20423    pub fn clear_background_highlights<T: 'static>(
20424        &mut self,
20425        cx: &mut Context<Self>,
20426    ) -> Option<BackgroundHighlight> {
20427        let text_highlights = self
20428            .background_highlights
20429            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20430        if !text_highlights.1.is_empty() {
20431            self.scrollbar_marker_state.dirty = true;
20432            cx.notify();
20433        }
20434        Some(text_highlights)
20435    }
20436
20437    pub fn highlight_gutter<T: 'static>(
20438        &mut self,
20439        ranges: impl Into<Vec<Range<Anchor>>>,
20440        color_fetcher: fn(&App) -> Hsla,
20441        cx: &mut Context<Self>,
20442    ) {
20443        self.gutter_highlights
20444            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20445        cx.notify();
20446    }
20447
20448    pub fn clear_gutter_highlights<T: 'static>(
20449        &mut self,
20450        cx: &mut Context<Self>,
20451    ) -> Option<GutterHighlight> {
20452        cx.notify();
20453        self.gutter_highlights.remove(&TypeId::of::<T>())
20454    }
20455
20456    pub fn insert_gutter_highlight<T: 'static>(
20457        &mut self,
20458        range: Range<Anchor>,
20459        color_fetcher: fn(&App) -> Hsla,
20460        cx: &mut Context<Self>,
20461    ) {
20462        let snapshot = self.buffer().read(cx).snapshot(cx);
20463        let mut highlights = self
20464            .gutter_highlights
20465            .remove(&TypeId::of::<T>())
20466            .map(|(_, highlights)| highlights)
20467            .unwrap_or_default();
20468        let ix = highlights.binary_search_by(|highlight| {
20469            Ordering::Equal
20470                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20471                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20472        });
20473        if let Err(ix) = ix {
20474            highlights.insert(ix, range);
20475        }
20476        self.gutter_highlights
20477            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20478    }
20479
20480    pub fn remove_gutter_highlights<T: 'static>(
20481        &mut self,
20482        ranges_to_remove: Vec<Range<Anchor>>,
20483        cx: &mut Context<Self>,
20484    ) {
20485        let snapshot = self.buffer().read(cx).snapshot(cx);
20486        let Some((color_fetcher, mut gutter_highlights)) =
20487            self.gutter_highlights.remove(&TypeId::of::<T>())
20488        else {
20489            return;
20490        };
20491        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20492        gutter_highlights.retain(|highlight| {
20493            while let Some(range_to_remove) = ranges_to_remove.peek() {
20494                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20495                    Ordering::Less | Ordering::Equal => {
20496                        ranges_to_remove.next();
20497                    }
20498                    Ordering::Greater => {
20499                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20500                            Ordering::Less | Ordering::Equal => {
20501                                return false;
20502                            }
20503                            Ordering::Greater => break,
20504                        }
20505                    }
20506                }
20507            }
20508
20509            true
20510        });
20511        self.gutter_highlights
20512            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20513    }
20514
20515    #[cfg(feature = "test-support")]
20516    pub fn all_text_highlights(
20517        &self,
20518        window: &mut Window,
20519        cx: &mut Context<Self>,
20520    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20521        let snapshot = self.snapshot(window, cx);
20522        self.display_map.update(cx, |display_map, _| {
20523            display_map
20524                .all_text_highlights()
20525                .map(|highlight| {
20526                    let (style, ranges) = highlight.as_ref();
20527                    (
20528                        *style,
20529                        ranges
20530                            .iter()
20531                            .map(|range| range.clone().to_display_points(&snapshot))
20532                            .collect(),
20533                    )
20534                })
20535                .collect()
20536        })
20537    }
20538
20539    #[cfg(feature = "test-support")]
20540    pub fn all_text_background_highlights(
20541        &self,
20542        window: &mut Window,
20543        cx: &mut Context<Self>,
20544    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20545        let snapshot = self.snapshot(window, cx);
20546        let buffer = &snapshot.buffer_snapshot();
20547        let start = buffer.anchor_before(0);
20548        let end = buffer.anchor_after(buffer.len());
20549        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20550    }
20551
20552    #[cfg(any(test, feature = "test-support"))]
20553    pub fn sorted_background_highlights_in_range(
20554        &self,
20555        search_range: Range<Anchor>,
20556        display_snapshot: &DisplaySnapshot,
20557        theme: &Theme,
20558    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20559        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20560        res.sort_by(|a, b| {
20561            a.0.start
20562                .cmp(&b.0.start)
20563                .then_with(|| a.0.end.cmp(&b.0.end))
20564                .then_with(|| a.1.cmp(&b.1))
20565        });
20566        res
20567    }
20568
20569    #[cfg(feature = "test-support")]
20570    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20571        let snapshot = self.buffer().read(cx).snapshot(cx);
20572
20573        let highlights = self
20574            .background_highlights
20575            .get(&HighlightKey::Type(TypeId::of::<
20576                items::BufferSearchHighlights,
20577            >()));
20578
20579        if let Some((_color, ranges)) = highlights {
20580            ranges
20581                .iter()
20582                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20583                .collect_vec()
20584        } else {
20585            vec![]
20586        }
20587    }
20588
20589    fn document_highlights_for_position<'a>(
20590        &'a self,
20591        position: Anchor,
20592        buffer: &'a MultiBufferSnapshot,
20593    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20594        let read_highlights = self
20595            .background_highlights
20596            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20597            .map(|h| &h.1);
20598        let write_highlights = self
20599            .background_highlights
20600            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20601            .map(|h| &h.1);
20602        let left_position = position.bias_left(buffer);
20603        let right_position = position.bias_right(buffer);
20604        read_highlights
20605            .into_iter()
20606            .chain(write_highlights)
20607            .flat_map(move |ranges| {
20608                let start_ix = match ranges.binary_search_by(|probe| {
20609                    let cmp = probe.end.cmp(&left_position, buffer);
20610                    if cmp.is_ge() {
20611                        Ordering::Greater
20612                    } else {
20613                        Ordering::Less
20614                    }
20615                }) {
20616                    Ok(i) | Err(i) => i,
20617                };
20618
20619                ranges[start_ix..]
20620                    .iter()
20621                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20622            })
20623    }
20624
20625    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20626        self.background_highlights
20627            .get(&HighlightKey::Type(TypeId::of::<T>()))
20628            .is_some_and(|(_, highlights)| !highlights.is_empty())
20629    }
20630
20631    /// Returns all background highlights for a given range.
20632    ///
20633    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20634    pub fn background_highlights_in_range(
20635        &self,
20636        search_range: Range<Anchor>,
20637        display_snapshot: &DisplaySnapshot,
20638        theme: &Theme,
20639    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20640        let mut results = Vec::new();
20641        for (color_fetcher, ranges) in self.background_highlights.values() {
20642            let color = color_fetcher(theme);
20643            let start_ix = match ranges.binary_search_by(|probe| {
20644                let cmp = probe
20645                    .end
20646                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20647                if cmp.is_gt() {
20648                    Ordering::Greater
20649                } else {
20650                    Ordering::Less
20651                }
20652            }) {
20653                Ok(i) | Err(i) => i,
20654            };
20655            for range in &ranges[start_ix..] {
20656                if range
20657                    .start
20658                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20659                    .is_ge()
20660                {
20661                    break;
20662                }
20663
20664                let start = range.start.to_display_point(display_snapshot);
20665                let end = range.end.to_display_point(display_snapshot);
20666                results.push((start..end, color))
20667            }
20668        }
20669        results
20670    }
20671
20672    pub fn gutter_highlights_in_range(
20673        &self,
20674        search_range: Range<Anchor>,
20675        display_snapshot: &DisplaySnapshot,
20676        cx: &App,
20677    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20678        let mut results = Vec::new();
20679        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20680            let color = color_fetcher(cx);
20681            let start_ix = match ranges.binary_search_by(|probe| {
20682                let cmp = probe
20683                    .end
20684                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20685                if cmp.is_gt() {
20686                    Ordering::Greater
20687                } else {
20688                    Ordering::Less
20689                }
20690            }) {
20691                Ok(i) | Err(i) => i,
20692            };
20693            for range in &ranges[start_ix..] {
20694                if range
20695                    .start
20696                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20697                    .is_ge()
20698                {
20699                    break;
20700                }
20701
20702                let start = range.start.to_display_point(display_snapshot);
20703                let end = range.end.to_display_point(display_snapshot);
20704                results.push((start..end, color))
20705            }
20706        }
20707        results
20708    }
20709
20710    /// Get the text ranges corresponding to the redaction query
20711    pub fn redacted_ranges(
20712        &self,
20713        search_range: Range<Anchor>,
20714        display_snapshot: &DisplaySnapshot,
20715        cx: &App,
20716    ) -> Vec<Range<DisplayPoint>> {
20717        display_snapshot
20718            .buffer_snapshot()
20719            .redacted_ranges(search_range, |file| {
20720                if let Some(file) = file {
20721                    file.is_private()
20722                        && EditorSettings::get(
20723                            Some(SettingsLocation {
20724                                worktree_id: file.worktree_id(cx),
20725                                path: file.path().as_ref(),
20726                            }),
20727                            cx,
20728                        )
20729                        .redact_private_values
20730                } else {
20731                    false
20732                }
20733            })
20734            .map(|range| {
20735                range.start.to_display_point(display_snapshot)
20736                    ..range.end.to_display_point(display_snapshot)
20737            })
20738            .collect()
20739    }
20740
20741    pub fn highlight_text_key<T: 'static>(
20742        &mut self,
20743        key: usize,
20744        ranges: Vec<Range<Anchor>>,
20745        style: HighlightStyle,
20746        cx: &mut Context<Self>,
20747    ) {
20748        self.display_map.update(cx, |map, _| {
20749            map.highlight_text(
20750                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20751                ranges,
20752                style,
20753            );
20754        });
20755        cx.notify();
20756    }
20757
20758    pub fn highlight_text<T: 'static>(
20759        &mut self,
20760        ranges: Vec<Range<Anchor>>,
20761        style: HighlightStyle,
20762        cx: &mut Context<Self>,
20763    ) {
20764        self.display_map.update(cx, |map, _| {
20765            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20766        });
20767        cx.notify();
20768    }
20769
20770    pub(crate) fn highlight_inlays<T: 'static>(
20771        &mut self,
20772        highlights: Vec<InlayHighlight>,
20773        style: HighlightStyle,
20774        cx: &mut Context<Self>,
20775    ) {
20776        self.display_map.update(cx, |map, _| {
20777            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20778        });
20779        cx.notify();
20780    }
20781
20782    pub fn text_highlights<'a, T: 'static>(
20783        &'a self,
20784        cx: &'a App,
20785    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20786        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20787    }
20788
20789    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20790        let cleared = self
20791            .display_map
20792            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20793        if cleared {
20794            cx.notify();
20795        }
20796    }
20797
20798    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20799        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20800            && self.focus_handle.is_focused(window)
20801    }
20802
20803    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20804        self.show_cursor_when_unfocused = is_enabled;
20805        cx.notify();
20806    }
20807
20808    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20809        cx.notify();
20810    }
20811
20812    fn on_debug_session_event(
20813        &mut self,
20814        _session: Entity<Session>,
20815        event: &SessionEvent,
20816        cx: &mut Context<Self>,
20817    ) {
20818        if let SessionEvent::InvalidateInlineValue = event {
20819            self.refresh_inline_values(cx);
20820        }
20821    }
20822
20823    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20824        let Some(project) = self.project.clone() else {
20825            return;
20826        };
20827
20828        if !self.inline_value_cache.enabled {
20829            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20830            self.splice_inlays(&inlays, Vec::new(), cx);
20831            return;
20832        }
20833
20834        let current_execution_position = self
20835            .highlighted_rows
20836            .get(&TypeId::of::<ActiveDebugLine>())
20837            .and_then(|lines| lines.last().map(|line| line.range.end));
20838
20839        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20840            let inline_values = editor
20841                .update(cx, |editor, cx| {
20842                    let Some(current_execution_position) = current_execution_position else {
20843                        return Some(Task::ready(Ok(Vec::new())));
20844                    };
20845
20846                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20847                        let snapshot = buffer.snapshot(cx);
20848
20849                        let excerpt = snapshot.excerpt_containing(
20850                            current_execution_position..current_execution_position,
20851                        )?;
20852
20853                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20854                    })?;
20855
20856                    let range =
20857                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20858
20859                    project.inline_values(buffer, range, cx)
20860                })
20861                .ok()
20862                .flatten()?
20863                .await
20864                .context("refreshing debugger inlays")
20865                .log_err()?;
20866
20867            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20868
20869            for (buffer_id, inline_value) in inline_values
20870                .into_iter()
20871                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20872            {
20873                buffer_inline_values
20874                    .entry(buffer_id)
20875                    .or_default()
20876                    .push(inline_value);
20877            }
20878
20879            editor
20880                .update(cx, |editor, cx| {
20881                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20882                    let mut new_inlays = Vec::default();
20883
20884                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20885                        let buffer_id = buffer_snapshot.remote_id();
20886                        buffer_inline_values
20887                            .get(&buffer_id)
20888                            .into_iter()
20889                            .flatten()
20890                            .for_each(|hint| {
20891                                let inlay = Inlay::debugger(
20892                                    post_inc(&mut editor.next_inlay_id),
20893                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20894                                    hint.text(),
20895                                );
20896                                if !inlay.text().chars().contains(&'\n') {
20897                                    new_inlays.push(inlay);
20898                                }
20899                            });
20900                    }
20901
20902                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20903                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20904
20905                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20906                })
20907                .ok()?;
20908            Some(())
20909        });
20910    }
20911
20912    fn on_buffer_event(
20913        &mut self,
20914        multibuffer: &Entity<MultiBuffer>,
20915        event: &multi_buffer::Event,
20916        window: &mut Window,
20917        cx: &mut Context<Self>,
20918    ) {
20919        match event {
20920            multi_buffer::Event::Edited { edited_buffer } => {
20921                self.scrollbar_marker_state.dirty = true;
20922                self.active_indent_guides_state.dirty = true;
20923                self.refresh_active_diagnostics(cx);
20924                self.refresh_code_actions(window, cx);
20925                self.refresh_selected_text_highlights(true, window, cx);
20926                self.refresh_single_line_folds(window, cx);
20927                refresh_matching_bracket_highlights(self, cx);
20928                if self.has_active_edit_prediction() {
20929                    self.update_visible_edit_prediction(window, cx);
20930                }
20931
20932                if let Some(edited_buffer) = edited_buffer {
20933                    if edited_buffer.read(cx).file().is_none() {
20934                        cx.emit(EditorEvent::TitleChanged);
20935                    }
20936
20937                    let buffer_id = edited_buffer.read(cx).remote_id();
20938                    if let Some(project) = self.project.clone() {
20939                        self.register_buffer(buffer_id, cx);
20940                        self.update_lsp_data(Some(buffer_id), window, cx);
20941                        #[allow(clippy::mutable_key_type)]
20942                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20943                            multibuffer
20944                                .all_buffers()
20945                                .into_iter()
20946                                .filter_map(|buffer| {
20947                                    buffer.update(cx, |buffer, cx| {
20948                                        let language = buffer.language()?;
20949                                        let should_discard = project.update(cx, |project, cx| {
20950                                            project.is_local()
20951                                                && !project.has_language_servers_for(buffer, cx)
20952                                        });
20953                                        should_discard.not().then_some(language.clone())
20954                                    })
20955                                })
20956                                .collect::<HashSet<_>>()
20957                        });
20958                        if !languages_affected.is_empty() {
20959                            self.refresh_inlay_hints(
20960                                InlayHintRefreshReason::BufferEdited(languages_affected),
20961                                cx,
20962                            );
20963                        }
20964                    }
20965                }
20966
20967                cx.emit(EditorEvent::BufferEdited);
20968                cx.emit(SearchEvent::MatchesInvalidated);
20969
20970                let Some(project) = &self.project else { return };
20971                let (telemetry, is_via_ssh) = {
20972                    let project = project.read(cx);
20973                    let telemetry = project.client().telemetry().clone();
20974                    let is_via_ssh = project.is_via_remote_server();
20975                    (telemetry, is_via_ssh)
20976                };
20977                telemetry.log_edit_event("editor", is_via_ssh);
20978            }
20979            multi_buffer::Event::ExcerptsAdded {
20980                buffer,
20981                predecessor,
20982                excerpts,
20983            } => {
20984                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20985                let buffer_id = buffer.read(cx).remote_id();
20986                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20987                    && let Some(project) = &self.project
20988                {
20989                    update_uncommitted_diff_for_buffer(
20990                        cx.entity(),
20991                        project,
20992                        [buffer.clone()],
20993                        self.buffer.clone(),
20994                        cx,
20995                    )
20996                    .detach();
20997                }
20998                self.update_lsp_data(Some(buffer_id), window, cx);
20999                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21000                cx.emit(EditorEvent::ExcerptsAdded {
21001                    buffer: buffer.clone(),
21002                    predecessor: *predecessor,
21003                    excerpts: excerpts.clone(),
21004                });
21005            }
21006            multi_buffer::Event::ExcerptsRemoved {
21007                ids,
21008                removed_buffer_ids,
21009            } => {
21010                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21011                for buffer_id in removed_buffer_ids {
21012                    self.registered_buffers.remove(buffer_id);
21013                }
21014                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21015                cx.emit(EditorEvent::ExcerptsRemoved {
21016                    ids: ids.clone(),
21017                    removed_buffer_ids: removed_buffer_ids.clone(),
21018                });
21019            }
21020            multi_buffer::Event::ExcerptsEdited {
21021                excerpt_ids,
21022                buffer_ids,
21023            } => {
21024                self.display_map.update(cx, |map, cx| {
21025                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21026                });
21027                cx.emit(EditorEvent::ExcerptsEdited {
21028                    ids: excerpt_ids.clone(),
21029                });
21030            }
21031            multi_buffer::Event::ExcerptsExpanded { ids } => {
21032                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21033                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21034            }
21035            multi_buffer::Event::Reparsed(buffer_id) => {
21036                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21037                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21038
21039                cx.emit(EditorEvent::Reparsed(*buffer_id));
21040            }
21041            multi_buffer::Event::DiffHunksToggled => {
21042                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21043            }
21044            multi_buffer::Event::LanguageChanged(buffer_id) => {
21045                self.registered_buffers.remove(&buffer_id);
21046                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21047                cx.emit(EditorEvent::Reparsed(*buffer_id));
21048                cx.notify();
21049            }
21050            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21051            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21052            multi_buffer::Event::FileHandleChanged
21053            | multi_buffer::Event::Reloaded
21054            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21055            multi_buffer::Event::DiagnosticsUpdated => {
21056                self.update_diagnostics_state(window, cx);
21057            }
21058            _ => {}
21059        };
21060    }
21061
21062    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21063        if !self.diagnostics_enabled() {
21064            return;
21065        }
21066        self.refresh_active_diagnostics(cx);
21067        self.refresh_inline_diagnostics(true, window, cx);
21068        self.scrollbar_marker_state.dirty = true;
21069        cx.notify();
21070    }
21071
21072    pub fn start_temporary_diff_override(&mut self) {
21073        self.load_diff_task.take();
21074        self.temporary_diff_override = true;
21075    }
21076
21077    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21078        self.temporary_diff_override = false;
21079        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21080        self.buffer.update(cx, |buffer, cx| {
21081            buffer.set_all_diff_hunks_collapsed(cx);
21082        });
21083
21084        if let Some(project) = self.project.clone() {
21085            self.load_diff_task = Some(
21086                update_uncommitted_diff_for_buffer(
21087                    cx.entity(),
21088                    &project,
21089                    self.buffer.read(cx).all_buffers(),
21090                    self.buffer.clone(),
21091                    cx,
21092                )
21093                .shared(),
21094            );
21095        }
21096    }
21097
21098    fn on_display_map_changed(
21099        &mut self,
21100        _: Entity<DisplayMap>,
21101        _: &mut Window,
21102        cx: &mut Context<Self>,
21103    ) {
21104        cx.notify();
21105    }
21106
21107    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21108        if self.diagnostics_enabled() {
21109            let new_severity = EditorSettings::get_global(cx)
21110                .diagnostics_max_severity
21111                .unwrap_or(DiagnosticSeverity::Hint);
21112            self.set_max_diagnostics_severity(new_severity, cx);
21113        }
21114        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21115        self.update_edit_prediction_settings(cx);
21116        self.refresh_edit_prediction(true, false, window, cx);
21117        self.refresh_inline_values(cx);
21118        self.refresh_inlay_hints(
21119            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21120                self.selections.newest_anchor().head(),
21121                &self.buffer.read(cx).snapshot(cx),
21122                cx,
21123            )),
21124            cx,
21125        );
21126
21127        let old_cursor_shape = self.cursor_shape;
21128        let old_show_breadcrumbs = self.show_breadcrumbs;
21129
21130        {
21131            let editor_settings = EditorSettings::get_global(cx);
21132            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21133            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21134            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21135            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21136        }
21137
21138        if old_cursor_shape != self.cursor_shape {
21139            cx.emit(EditorEvent::CursorShapeChanged);
21140        }
21141
21142        if old_show_breadcrumbs != self.show_breadcrumbs {
21143            cx.emit(EditorEvent::BreadcrumbsChanged);
21144        }
21145
21146        let project_settings = ProjectSettings::get_global(cx);
21147        self.serialize_dirty_buffers =
21148            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21149
21150        if self.mode.is_full() {
21151            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21152            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21153            if self.show_inline_diagnostics != show_inline_diagnostics {
21154                self.show_inline_diagnostics = show_inline_diagnostics;
21155                self.refresh_inline_diagnostics(false, window, cx);
21156            }
21157
21158            if self.git_blame_inline_enabled != inline_blame_enabled {
21159                self.toggle_git_blame_inline_internal(false, window, cx);
21160            }
21161
21162            let minimap_settings = EditorSettings::get_global(cx).minimap;
21163            if self.minimap_visibility != MinimapVisibility::Disabled {
21164                if self.minimap_visibility.settings_visibility()
21165                    != minimap_settings.minimap_enabled()
21166                {
21167                    self.set_minimap_visibility(
21168                        MinimapVisibility::for_mode(self.mode(), cx),
21169                        window,
21170                        cx,
21171                    );
21172                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21173                    minimap_entity.update(cx, |minimap_editor, cx| {
21174                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21175                    })
21176                }
21177            }
21178        }
21179
21180        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21181            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21182        }) {
21183            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21184                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21185            }
21186            self.refresh_colors_for_visible_range(None, window, cx);
21187        }
21188
21189        cx.notify();
21190    }
21191
21192    pub fn set_searchable(&mut self, searchable: bool) {
21193        self.searchable = searchable;
21194    }
21195
21196    pub fn searchable(&self) -> bool {
21197        self.searchable
21198    }
21199
21200    fn open_proposed_changes_editor(
21201        &mut self,
21202        _: &OpenProposedChangesEditor,
21203        window: &mut Window,
21204        cx: &mut Context<Self>,
21205    ) {
21206        let Some(workspace) = self.workspace() else {
21207            cx.propagate();
21208            return;
21209        };
21210
21211        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21212        let multi_buffer = self.buffer.read(cx);
21213        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21214        let mut new_selections_by_buffer = HashMap::default();
21215        for selection in selections {
21216            for (buffer, range, _) in
21217                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21218            {
21219                let mut range = range.to_point(buffer);
21220                range.start.column = 0;
21221                range.end.column = buffer.line_len(range.end.row);
21222                new_selections_by_buffer
21223                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21224                    .or_insert(Vec::new())
21225                    .push(range)
21226            }
21227        }
21228
21229        let proposed_changes_buffers = new_selections_by_buffer
21230            .into_iter()
21231            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21232            .collect::<Vec<_>>();
21233        let proposed_changes_editor = cx.new(|cx| {
21234            ProposedChangesEditor::new(
21235                "Proposed changes",
21236                proposed_changes_buffers,
21237                self.project.clone(),
21238                window,
21239                cx,
21240            )
21241        });
21242
21243        window.defer(cx, move |window, cx| {
21244            workspace.update(cx, |workspace, cx| {
21245                workspace.active_pane().update(cx, |pane, cx| {
21246                    pane.add_item(
21247                        Box::new(proposed_changes_editor),
21248                        true,
21249                        true,
21250                        None,
21251                        window,
21252                        cx,
21253                    );
21254                });
21255            });
21256        });
21257    }
21258
21259    pub fn open_excerpts_in_split(
21260        &mut self,
21261        _: &OpenExcerptsSplit,
21262        window: &mut Window,
21263        cx: &mut Context<Self>,
21264    ) {
21265        self.open_excerpts_common(None, true, window, cx)
21266    }
21267
21268    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21269        self.open_excerpts_common(None, false, window, cx)
21270    }
21271
21272    fn open_excerpts_common(
21273        &mut self,
21274        jump_data: Option<JumpData>,
21275        split: bool,
21276        window: &mut Window,
21277        cx: &mut Context<Self>,
21278    ) {
21279        let Some(workspace) = self.workspace() else {
21280            cx.propagate();
21281            return;
21282        };
21283
21284        if self.buffer.read(cx).is_singleton() {
21285            cx.propagate();
21286            return;
21287        }
21288
21289        let mut new_selections_by_buffer = HashMap::default();
21290        match &jump_data {
21291            Some(JumpData::MultiBufferPoint {
21292                excerpt_id,
21293                position,
21294                anchor,
21295                line_offset_from_top,
21296            }) => {
21297                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21298                if let Some(buffer) = multi_buffer_snapshot
21299                    .buffer_id_for_excerpt(*excerpt_id)
21300                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21301                {
21302                    let buffer_snapshot = buffer.read(cx).snapshot();
21303                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21304                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21305                    } else {
21306                        buffer_snapshot.clip_point(*position, Bias::Left)
21307                    };
21308                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21309                    new_selections_by_buffer.insert(
21310                        buffer,
21311                        (
21312                            vec![jump_to_offset..jump_to_offset],
21313                            Some(*line_offset_from_top),
21314                        ),
21315                    );
21316                }
21317            }
21318            Some(JumpData::MultiBufferRow {
21319                row,
21320                line_offset_from_top,
21321            }) => {
21322                let point = MultiBufferPoint::new(row.0, 0);
21323                if let Some((buffer, buffer_point, _)) =
21324                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21325                {
21326                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21327                    new_selections_by_buffer
21328                        .entry(buffer)
21329                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21330                        .0
21331                        .push(buffer_offset..buffer_offset)
21332                }
21333            }
21334            None => {
21335                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21336                let multi_buffer = self.buffer.read(cx);
21337                for selection in selections {
21338                    for (snapshot, range, _, anchor) in multi_buffer
21339                        .snapshot(cx)
21340                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21341                    {
21342                        if let Some(anchor) = anchor {
21343                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21344                            else {
21345                                continue;
21346                            };
21347                            let offset = text::ToOffset::to_offset(
21348                                &anchor.text_anchor,
21349                                &buffer_handle.read(cx).snapshot(),
21350                            );
21351                            let range = offset..offset;
21352                            new_selections_by_buffer
21353                                .entry(buffer_handle)
21354                                .or_insert((Vec::new(), None))
21355                                .0
21356                                .push(range)
21357                        } else {
21358                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21359                            else {
21360                                continue;
21361                            };
21362                            new_selections_by_buffer
21363                                .entry(buffer_handle)
21364                                .or_insert((Vec::new(), None))
21365                                .0
21366                                .push(range)
21367                        }
21368                    }
21369                }
21370            }
21371        }
21372
21373        new_selections_by_buffer
21374            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21375
21376        if new_selections_by_buffer.is_empty() {
21377            return;
21378        }
21379
21380        // We defer the pane interaction because we ourselves are a workspace item
21381        // and activating a new item causes the pane to call a method on us reentrantly,
21382        // which panics if we're on the stack.
21383        window.defer(cx, move |window, cx| {
21384            workspace.update(cx, |workspace, cx| {
21385                let pane = if split {
21386                    workspace.adjacent_pane(window, cx)
21387                } else {
21388                    workspace.active_pane().clone()
21389                };
21390
21391                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21392                    let editor = buffer
21393                        .read(cx)
21394                        .file()
21395                        .is_none()
21396                        .then(|| {
21397                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21398                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21399                            // Instead, we try to activate the existing editor in the pane first.
21400                            let (editor, pane_item_index) =
21401                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21402                                    let editor = item.downcast::<Editor>()?;
21403                                    let singleton_buffer =
21404                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21405                                    if singleton_buffer == buffer {
21406                                        Some((editor, i))
21407                                    } else {
21408                                        None
21409                                    }
21410                                })?;
21411                            pane.update(cx, |pane, cx| {
21412                                pane.activate_item(pane_item_index, true, true, window, cx)
21413                            });
21414                            Some(editor)
21415                        })
21416                        .flatten()
21417                        .unwrap_or_else(|| {
21418                            workspace.open_project_item::<Self>(
21419                                pane.clone(),
21420                                buffer,
21421                                true,
21422                                true,
21423                                window,
21424                                cx,
21425                            )
21426                        });
21427
21428                    editor.update(cx, |editor, cx| {
21429                        let autoscroll = match scroll_offset {
21430                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21431                            None => Autoscroll::newest(),
21432                        };
21433                        let nav_history = editor.nav_history.take();
21434                        editor.change_selections(
21435                            SelectionEffects::scroll(autoscroll),
21436                            window,
21437                            cx,
21438                            |s| {
21439                                s.select_ranges(ranges);
21440                            },
21441                        );
21442                        editor.nav_history = nav_history;
21443                    });
21444                }
21445            })
21446        });
21447    }
21448
21449    // For now, don't allow opening excerpts in buffers that aren't backed by
21450    // regular project files.
21451    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21452        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21453    }
21454
21455    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21456        let snapshot = self.buffer.read(cx).read(cx);
21457        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21458        Some(
21459            ranges
21460                .iter()
21461                .map(move |range| {
21462                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21463                })
21464                .collect(),
21465        )
21466    }
21467
21468    fn selection_replacement_ranges(
21469        &self,
21470        range: Range<OffsetUtf16>,
21471        cx: &mut App,
21472    ) -> Vec<Range<OffsetUtf16>> {
21473        let selections = self
21474            .selections
21475            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21476        let newest_selection = selections
21477            .iter()
21478            .max_by_key(|selection| selection.id)
21479            .unwrap();
21480        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21481        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21482        let snapshot = self.buffer.read(cx).read(cx);
21483        selections
21484            .into_iter()
21485            .map(|mut selection| {
21486                selection.start.0 =
21487                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21488                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21489                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21490                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21491            })
21492            .collect()
21493    }
21494
21495    fn report_editor_event(
21496        &self,
21497        reported_event: ReportEditorEvent,
21498        file_extension: Option<String>,
21499        cx: &App,
21500    ) {
21501        if cfg!(any(test, feature = "test-support")) {
21502            return;
21503        }
21504
21505        let Some(project) = &self.project else { return };
21506
21507        // If None, we are in a file without an extension
21508        let file = self
21509            .buffer
21510            .read(cx)
21511            .as_singleton()
21512            .and_then(|b| b.read(cx).file());
21513        let file_extension = file_extension.or(file
21514            .as_ref()
21515            .and_then(|file| Path::new(file.file_name(cx)).extension())
21516            .and_then(|e| e.to_str())
21517            .map(|a| a.to_string()));
21518
21519        let vim_mode = vim_enabled(cx);
21520
21521        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21522        let copilot_enabled = edit_predictions_provider
21523            == language::language_settings::EditPredictionProvider::Copilot;
21524        let copilot_enabled_for_language = self
21525            .buffer
21526            .read(cx)
21527            .language_settings(cx)
21528            .show_edit_predictions;
21529
21530        let project = project.read(cx);
21531        let event_type = reported_event.event_type();
21532
21533        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21534            telemetry::event!(
21535                event_type,
21536                type = if auto_saved {"autosave"} else {"manual"},
21537                file_extension,
21538                vim_mode,
21539                copilot_enabled,
21540                copilot_enabled_for_language,
21541                edit_predictions_provider,
21542                is_via_ssh = project.is_via_remote_server(),
21543            );
21544        } else {
21545            telemetry::event!(
21546                event_type,
21547                file_extension,
21548                vim_mode,
21549                copilot_enabled,
21550                copilot_enabled_for_language,
21551                edit_predictions_provider,
21552                is_via_ssh = project.is_via_remote_server(),
21553            );
21554        };
21555    }
21556
21557    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21558    /// with each line being an array of {text, highlight} objects.
21559    fn copy_highlight_json(
21560        &mut self,
21561        _: &CopyHighlightJson,
21562        window: &mut Window,
21563        cx: &mut Context<Self>,
21564    ) {
21565        #[derive(Serialize)]
21566        struct Chunk<'a> {
21567            text: String,
21568            highlight: Option<&'a str>,
21569        }
21570
21571        let snapshot = self.buffer.read(cx).snapshot(cx);
21572        let range = self
21573            .selected_text_range(false, window, cx)
21574            .and_then(|selection| {
21575                if selection.range.is_empty() {
21576                    None
21577                } else {
21578                    Some(selection.range)
21579                }
21580            })
21581            .unwrap_or_else(|| 0..snapshot.len());
21582
21583        let chunks = snapshot.chunks(range, true);
21584        let mut lines = Vec::new();
21585        let mut line: VecDeque<Chunk> = VecDeque::new();
21586
21587        let Some(style) = self.style.as_ref() else {
21588            return;
21589        };
21590
21591        for chunk in chunks {
21592            let highlight = chunk
21593                .syntax_highlight_id
21594                .and_then(|id| id.name(&style.syntax));
21595            let mut chunk_lines = chunk.text.split('\n').peekable();
21596            while let Some(text) = chunk_lines.next() {
21597                let mut merged_with_last_token = false;
21598                if let Some(last_token) = line.back_mut()
21599                    && last_token.highlight == highlight
21600                {
21601                    last_token.text.push_str(text);
21602                    merged_with_last_token = true;
21603                }
21604
21605                if !merged_with_last_token {
21606                    line.push_back(Chunk {
21607                        text: text.into(),
21608                        highlight,
21609                    });
21610                }
21611
21612                if chunk_lines.peek().is_some() {
21613                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21614                        line.pop_front();
21615                    }
21616                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21617                        line.pop_back();
21618                    }
21619
21620                    lines.push(mem::take(&mut line));
21621                }
21622            }
21623        }
21624
21625        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21626            return;
21627        };
21628        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21629    }
21630
21631    pub fn open_context_menu(
21632        &mut self,
21633        _: &OpenContextMenu,
21634        window: &mut Window,
21635        cx: &mut Context<Self>,
21636    ) {
21637        self.request_autoscroll(Autoscroll::newest(), cx);
21638        let position = self
21639            .selections
21640            .newest_display(&self.display_snapshot(cx))
21641            .start;
21642        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21643    }
21644
21645    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21646        &self.inlay_hint_cache
21647    }
21648
21649    pub fn replay_insert_event(
21650        &mut self,
21651        text: &str,
21652        relative_utf16_range: Option<Range<isize>>,
21653        window: &mut Window,
21654        cx: &mut Context<Self>,
21655    ) {
21656        if !self.input_enabled {
21657            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21658            return;
21659        }
21660        if let Some(relative_utf16_range) = relative_utf16_range {
21661            let selections = self
21662                .selections
21663                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21664            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21665                let new_ranges = selections.into_iter().map(|range| {
21666                    let start = OffsetUtf16(
21667                        range
21668                            .head()
21669                            .0
21670                            .saturating_add_signed(relative_utf16_range.start),
21671                    );
21672                    let end = OffsetUtf16(
21673                        range
21674                            .head()
21675                            .0
21676                            .saturating_add_signed(relative_utf16_range.end),
21677                    );
21678                    start..end
21679                });
21680                s.select_ranges(new_ranges);
21681            });
21682        }
21683
21684        self.handle_input(text, window, cx);
21685    }
21686
21687    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21688        let Some(provider) = self.semantics_provider.as_ref() else {
21689            return false;
21690        };
21691
21692        let mut supports = false;
21693        self.buffer().update(cx, |this, cx| {
21694            this.for_each_buffer(|buffer| {
21695                supports |= provider.supports_inlay_hints(buffer, cx);
21696            });
21697        });
21698
21699        supports
21700    }
21701
21702    pub fn is_focused(&self, window: &Window) -> bool {
21703        self.focus_handle.is_focused(window)
21704    }
21705
21706    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21707        cx.emit(EditorEvent::Focused);
21708
21709        if let Some(descendant) = self
21710            .last_focused_descendant
21711            .take()
21712            .and_then(|descendant| descendant.upgrade())
21713        {
21714            window.focus(&descendant);
21715        } else {
21716            if let Some(blame) = self.blame.as_ref() {
21717                blame.update(cx, GitBlame::focus)
21718            }
21719
21720            self.blink_manager.update(cx, BlinkManager::enable);
21721            self.show_cursor_names(window, cx);
21722            self.buffer.update(cx, |buffer, cx| {
21723                buffer.finalize_last_transaction(cx);
21724                if self.leader_id.is_none() {
21725                    buffer.set_active_selections(
21726                        &self.selections.disjoint_anchors_arc(),
21727                        self.selections.line_mode(),
21728                        self.cursor_shape,
21729                        cx,
21730                    );
21731                }
21732            });
21733        }
21734    }
21735
21736    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21737        cx.emit(EditorEvent::FocusedIn)
21738    }
21739
21740    fn handle_focus_out(
21741        &mut self,
21742        event: FocusOutEvent,
21743        _window: &mut Window,
21744        cx: &mut Context<Self>,
21745    ) {
21746        if event.blurred != self.focus_handle {
21747            self.last_focused_descendant = Some(event.blurred);
21748        }
21749        self.selection_drag_state = SelectionDragState::None;
21750        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21751    }
21752
21753    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21754        self.blink_manager.update(cx, BlinkManager::disable);
21755        self.buffer
21756            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21757
21758        if let Some(blame) = self.blame.as_ref() {
21759            blame.update(cx, GitBlame::blur)
21760        }
21761        if !self.hover_state.focused(window, cx) {
21762            hide_hover(self, cx);
21763        }
21764        if !self
21765            .context_menu
21766            .borrow()
21767            .as_ref()
21768            .is_some_and(|context_menu| context_menu.focused(window, cx))
21769        {
21770            self.hide_context_menu(window, cx);
21771        }
21772        self.take_active_edit_prediction(cx);
21773        cx.emit(EditorEvent::Blurred);
21774        cx.notify();
21775    }
21776
21777    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21778        let mut pending: String = window
21779            .pending_input_keystrokes()
21780            .into_iter()
21781            .flatten()
21782            .filter_map(|keystroke| {
21783                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21784                    keystroke.key_char.clone()
21785                } else {
21786                    None
21787                }
21788            })
21789            .collect();
21790
21791        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21792            pending = "".to_string();
21793        }
21794
21795        let existing_pending = self
21796            .text_highlights::<PendingInput>(cx)
21797            .map(|(_, ranges)| ranges.to_vec());
21798        if existing_pending.is_none() && pending.is_empty() {
21799            return;
21800        }
21801        let transaction =
21802            self.transact(window, cx, |this, window, cx| {
21803                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21804                let edits = selections
21805                    .iter()
21806                    .map(|selection| (selection.end..selection.end, pending.clone()));
21807                this.edit(edits, cx);
21808                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21809                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21810                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21811                    }));
21812                });
21813                if let Some(existing_ranges) = existing_pending {
21814                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21815                    this.edit(edits, cx);
21816                }
21817            });
21818
21819        let snapshot = self.snapshot(window, cx);
21820        let ranges = self
21821            .selections
21822            .all::<usize>(&snapshot.display_snapshot)
21823            .into_iter()
21824            .map(|selection| {
21825                snapshot.buffer_snapshot().anchor_after(selection.end)
21826                    ..snapshot
21827                        .buffer_snapshot()
21828                        .anchor_before(selection.end + pending.len())
21829            })
21830            .collect();
21831
21832        if pending.is_empty() {
21833            self.clear_highlights::<PendingInput>(cx);
21834        } else {
21835            self.highlight_text::<PendingInput>(
21836                ranges,
21837                HighlightStyle {
21838                    underline: Some(UnderlineStyle {
21839                        thickness: px(1.),
21840                        color: None,
21841                        wavy: false,
21842                    }),
21843                    ..Default::default()
21844                },
21845                cx,
21846            );
21847        }
21848
21849        self.ime_transaction = self.ime_transaction.or(transaction);
21850        if let Some(transaction) = self.ime_transaction {
21851            self.buffer.update(cx, |buffer, cx| {
21852                buffer.group_until_transaction(transaction, cx);
21853            });
21854        }
21855
21856        if self.text_highlights::<PendingInput>(cx).is_none() {
21857            self.ime_transaction.take();
21858        }
21859    }
21860
21861    pub fn register_action_renderer(
21862        &mut self,
21863        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21864    ) -> Subscription {
21865        let id = self.next_editor_action_id.post_inc();
21866        self.editor_actions
21867            .borrow_mut()
21868            .insert(id, Box::new(listener));
21869
21870        let editor_actions = self.editor_actions.clone();
21871        Subscription::new(move || {
21872            editor_actions.borrow_mut().remove(&id);
21873        })
21874    }
21875
21876    pub fn register_action<A: Action>(
21877        &mut self,
21878        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21879    ) -> Subscription {
21880        let id = self.next_editor_action_id.post_inc();
21881        let listener = Arc::new(listener);
21882        self.editor_actions.borrow_mut().insert(
21883            id,
21884            Box::new(move |_, window, _| {
21885                let listener = listener.clone();
21886                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21887                    let action = action.downcast_ref().unwrap();
21888                    if phase == DispatchPhase::Bubble {
21889                        listener(action, window, cx)
21890                    }
21891                })
21892            }),
21893        );
21894
21895        let editor_actions = self.editor_actions.clone();
21896        Subscription::new(move || {
21897            editor_actions.borrow_mut().remove(&id);
21898        })
21899    }
21900
21901    pub fn file_header_size(&self) -> u32 {
21902        FILE_HEADER_HEIGHT
21903    }
21904
21905    pub fn restore(
21906        &mut self,
21907        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21908        window: &mut Window,
21909        cx: &mut Context<Self>,
21910    ) {
21911        let workspace = self.workspace();
21912        let project = self.project();
21913        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21914            let mut tasks = Vec::new();
21915            for (buffer_id, changes) in revert_changes {
21916                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21917                    buffer.update(cx, |buffer, cx| {
21918                        buffer.edit(
21919                            changes
21920                                .into_iter()
21921                                .map(|(range, text)| (range, text.to_string())),
21922                            None,
21923                            cx,
21924                        );
21925                    });
21926
21927                    if let Some(project) =
21928                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21929                    {
21930                        project.update(cx, |project, cx| {
21931                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21932                        })
21933                    }
21934                }
21935            }
21936            tasks
21937        });
21938        cx.spawn_in(window, async move |_, cx| {
21939            for (buffer, task) in save_tasks {
21940                let result = task.await;
21941                if result.is_err() {
21942                    let Some(path) = buffer
21943                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21944                        .ok()
21945                    else {
21946                        continue;
21947                    };
21948                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21949                        let Some(task) = cx
21950                            .update_window_entity(workspace, |workspace, window, cx| {
21951                                workspace
21952                                    .open_path_preview(path, None, false, false, false, window, cx)
21953                            })
21954                            .ok()
21955                        else {
21956                            continue;
21957                        };
21958                        task.await.log_err();
21959                    }
21960                }
21961            }
21962        })
21963        .detach();
21964        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21965            selections.refresh()
21966        });
21967    }
21968
21969    pub fn to_pixel_point(
21970        &self,
21971        source: multi_buffer::Anchor,
21972        editor_snapshot: &EditorSnapshot,
21973        window: &mut Window,
21974    ) -> Option<gpui::Point<Pixels>> {
21975        let source_point = source.to_display_point(editor_snapshot);
21976        self.display_to_pixel_point(source_point, editor_snapshot, window)
21977    }
21978
21979    pub fn display_to_pixel_point(
21980        &self,
21981        source: DisplayPoint,
21982        editor_snapshot: &EditorSnapshot,
21983        window: &mut Window,
21984    ) -> Option<gpui::Point<Pixels>> {
21985        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21986        let text_layout_details = self.text_layout_details(window);
21987        let scroll_top = text_layout_details
21988            .scroll_anchor
21989            .scroll_position(editor_snapshot)
21990            .y;
21991
21992        if source.row().as_f64() < scroll_top.floor() {
21993            return None;
21994        }
21995        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21996        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21997        Some(gpui::Point::new(source_x, source_y))
21998    }
21999
22000    pub fn has_visible_completions_menu(&self) -> bool {
22001        !self.edit_prediction_preview_is_active()
22002            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22003                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22004            })
22005    }
22006
22007    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22008        if self.mode.is_minimap() {
22009            return;
22010        }
22011        self.addons
22012            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22013    }
22014
22015    pub fn unregister_addon<T: Addon>(&mut self) {
22016        self.addons.remove(&std::any::TypeId::of::<T>());
22017    }
22018
22019    pub fn addon<T: Addon>(&self) -> Option<&T> {
22020        let type_id = std::any::TypeId::of::<T>();
22021        self.addons
22022            .get(&type_id)
22023            .and_then(|item| item.to_any().downcast_ref::<T>())
22024    }
22025
22026    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22027        let type_id = std::any::TypeId::of::<T>();
22028        self.addons
22029            .get_mut(&type_id)
22030            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22031    }
22032
22033    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22034        let text_layout_details = self.text_layout_details(window);
22035        let style = &text_layout_details.editor_style;
22036        let font_id = window.text_system().resolve_font(&style.text.font());
22037        let font_size = style.text.font_size.to_pixels(window.rem_size());
22038        let line_height = style.text.line_height_in_pixels(window.rem_size());
22039        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22040        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22041
22042        CharacterDimensions {
22043            em_width,
22044            em_advance,
22045            line_height,
22046        }
22047    }
22048
22049    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22050        self.load_diff_task.clone()
22051    }
22052
22053    fn read_metadata_from_db(
22054        &mut self,
22055        item_id: u64,
22056        workspace_id: WorkspaceId,
22057        window: &mut Window,
22058        cx: &mut Context<Editor>,
22059    ) {
22060        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22061            && !self.mode.is_minimap()
22062            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22063        {
22064            let buffer_snapshot = OnceCell::new();
22065
22066            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22067                && !folds.is_empty()
22068            {
22069                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22070                self.fold_ranges(
22071                    folds
22072                        .into_iter()
22073                        .map(|(start, end)| {
22074                            snapshot.clip_offset(start, Bias::Left)
22075                                ..snapshot.clip_offset(end, Bias::Right)
22076                        })
22077                        .collect(),
22078                    false,
22079                    window,
22080                    cx,
22081                );
22082            }
22083
22084            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22085                && !selections.is_empty()
22086            {
22087                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22088                // skip adding the initial selection to selection history
22089                self.selection_history.mode = SelectionHistoryMode::Skipping;
22090                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22091                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22092                        snapshot.clip_offset(start, Bias::Left)
22093                            ..snapshot.clip_offset(end, Bias::Right)
22094                    }));
22095                });
22096                self.selection_history.mode = SelectionHistoryMode::Normal;
22097            };
22098        }
22099
22100        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22101    }
22102
22103    fn update_lsp_data(
22104        &mut self,
22105        for_buffer: Option<BufferId>,
22106        window: &mut Window,
22107        cx: &mut Context<'_, Self>,
22108    ) {
22109        self.pull_diagnostics(for_buffer, window, cx);
22110        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22111    }
22112
22113    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22114        if self.ignore_lsp_data() {
22115            return;
22116        }
22117        for (_, (visible_buffer, _, _)) in self.visible_excerpts(None, cx) {
22118            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22119        }
22120    }
22121
22122    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) -> bool {
22123        if !self.registered_buffers.contains_key(&buffer_id)
22124            && let Some(project) = self.project.as_ref()
22125        {
22126            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22127                project.update(cx, |project, cx| {
22128                    self.registered_buffers.insert(
22129                        buffer_id,
22130                        project.register_buffer_with_language_servers(&buffer, cx),
22131                    );
22132                });
22133                return true;
22134            } else {
22135                self.registered_buffers.remove(&buffer_id);
22136            }
22137        }
22138
22139        false
22140    }
22141
22142    fn ignore_lsp_data(&self) -> bool {
22143        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22144        // skip any LSP updates for it.
22145        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22146    }
22147}
22148
22149fn edit_for_markdown_paste<'a>(
22150    buffer: &MultiBufferSnapshot,
22151    range: Range<usize>,
22152    to_insert: &'a str,
22153    url: Option<url::Url>,
22154) -> (Range<usize>, Cow<'a, str>) {
22155    if url.is_none() {
22156        return (range, Cow::Borrowed(to_insert));
22157    };
22158
22159    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22160
22161    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22162        Cow::Borrowed(to_insert)
22163    } else {
22164        Cow::Owned(format!("[{old_text}]({to_insert})"))
22165    };
22166    (range, new_text)
22167}
22168
22169fn vim_enabled(cx: &App) -> bool {
22170    vim_mode_setting::VimModeSetting::try_get(cx)
22171        .map(|vim_mode| vim_mode.0)
22172        .unwrap_or(false)
22173}
22174
22175fn process_completion_for_edit(
22176    completion: &Completion,
22177    intent: CompletionIntent,
22178    buffer: &Entity<Buffer>,
22179    cursor_position: &text::Anchor,
22180    cx: &mut Context<Editor>,
22181) -> CompletionEdit {
22182    let buffer = buffer.read(cx);
22183    let buffer_snapshot = buffer.snapshot();
22184    let (snippet, new_text) = if completion.is_snippet() {
22185        let mut snippet_source = completion.new_text.clone();
22186        // Workaround for typescript language server issues so that methods don't expand within
22187        // strings and functions with type expressions. The previous point is used because the query
22188        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22189        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22190        let previous_point = if previous_point.column > 0 {
22191            cursor_position.to_previous_offset(&buffer_snapshot)
22192        } else {
22193            cursor_position.to_offset(&buffer_snapshot)
22194        };
22195        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22196            && scope.prefers_label_for_snippet_in_completion()
22197            && let Some(label) = completion.label()
22198            && matches!(
22199                completion.kind(),
22200                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22201            )
22202        {
22203            snippet_source = label;
22204        }
22205        match Snippet::parse(&snippet_source).log_err() {
22206            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22207            None => (None, completion.new_text.clone()),
22208        }
22209    } else {
22210        (None, completion.new_text.clone())
22211    };
22212
22213    let mut range_to_replace = {
22214        let replace_range = &completion.replace_range;
22215        if let CompletionSource::Lsp {
22216            insert_range: Some(insert_range),
22217            ..
22218        } = &completion.source
22219        {
22220            debug_assert_eq!(
22221                insert_range.start, replace_range.start,
22222                "insert_range and replace_range should start at the same position"
22223            );
22224            debug_assert!(
22225                insert_range
22226                    .start
22227                    .cmp(cursor_position, &buffer_snapshot)
22228                    .is_le(),
22229                "insert_range should start before or at cursor position"
22230            );
22231            debug_assert!(
22232                replace_range
22233                    .start
22234                    .cmp(cursor_position, &buffer_snapshot)
22235                    .is_le(),
22236                "replace_range should start before or at cursor position"
22237            );
22238
22239            let should_replace = match intent {
22240                CompletionIntent::CompleteWithInsert => false,
22241                CompletionIntent::CompleteWithReplace => true,
22242                CompletionIntent::Complete | CompletionIntent::Compose => {
22243                    let insert_mode =
22244                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22245                            .completions
22246                            .lsp_insert_mode;
22247                    match insert_mode {
22248                        LspInsertMode::Insert => false,
22249                        LspInsertMode::Replace => true,
22250                        LspInsertMode::ReplaceSubsequence => {
22251                            let mut text_to_replace = buffer.chars_for_range(
22252                                buffer.anchor_before(replace_range.start)
22253                                    ..buffer.anchor_after(replace_range.end),
22254                            );
22255                            let mut current_needle = text_to_replace.next();
22256                            for haystack_ch in completion.label.text.chars() {
22257                                if let Some(needle_ch) = current_needle
22258                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22259                                {
22260                                    current_needle = text_to_replace.next();
22261                                }
22262                            }
22263                            current_needle.is_none()
22264                        }
22265                        LspInsertMode::ReplaceSuffix => {
22266                            if replace_range
22267                                .end
22268                                .cmp(cursor_position, &buffer_snapshot)
22269                                .is_gt()
22270                            {
22271                                let range_after_cursor = *cursor_position..replace_range.end;
22272                                let text_after_cursor = buffer
22273                                    .text_for_range(
22274                                        buffer.anchor_before(range_after_cursor.start)
22275                                            ..buffer.anchor_after(range_after_cursor.end),
22276                                    )
22277                                    .collect::<String>()
22278                                    .to_ascii_lowercase();
22279                                completion
22280                                    .label
22281                                    .text
22282                                    .to_ascii_lowercase()
22283                                    .ends_with(&text_after_cursor)
22284                            } else {
22285                                true
22286                            }
22287                        }
22288                    }
22289                }
22290            };
22291
22292            if should_replace {
22293                replace_range.clone()
22294            } else {
22295                insert_range.clone()
22296            }
22297        } else {
22298            replace_range.clone()
22299        }
22300    };
22301
22302    if range_to_replace
22303        .end
22304        .cmp(cursor_position, &buffer_snapshot)
22305        .is_lt()
22306    {
22307        range_to_replace.end = *cursor_position;
22308    }
22309
22310    CompletionEdit {
22311        new_text,
22312        replace_range: range_to_replace.to_offset(buffer),
22313        snippet,
22314    }
22315}
22316
22317struct CompletionEdit {
22318    new_text: String,
22319    replace_range: Range<usize>,
22320    snippet: Option<Snippet>,
22321}
22322
22323fn insert_extra_newline_brackets(
22324    buffer: &MultiBufferSnapshot,
22325    range: Range<usize>,
22326    language: &language::LanguageScope,
22327) -> bool {
22328    let leading_whitespace_len = buffer
22329        .reversed_chars_at(range.start)
22330        .take_while(|c| c.is_whitespace() && *c != '\n')
22331        .map(|c| c.len_utf8())
22332        .sum::<usize>();
22333    let trailing_whitespace_len = buffer
22334        .chars_at(range.end)
22335        .take_while(|c| c.is_whitespace() && *c != '\n')
22336        .map(|c| c.len_utf8())
22337        .sum::<usize>();
22338    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22339
22340    language.brackets().any(|(pair, enabled)| {
22341        let pair_start = pair.start.trim_end();
22342        let pair_end = pair.end.trim_start();
22343
22344        enabled
22345            && pair.newline
22346            && buffer.contains_str_at(range.end, pair_end)
22347            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22348    })
22349}
22350
22351fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22352    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22353        [(buffer, range, _)] => (*buffer, range.clone()),
22354        _ => return false,
22355    };
22356    let pair = {
22357        let mut result: Option<BracketMatch> = None;
22358
22359        for pair in buffer
22360            .all_bracket_ranges(range.clone())
22361            .filter(move |pair| {
22362                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22363            })
22364        {
22365            let len = pair.close_range.end - pair.open_range.start;
22366
22367            if let Some(existing) = &result {
22368                let existing_len = existing.close_range.end - existing.open_range.start;
22369                if len > existing_len {
22370                    continue;
22371                }
22372            }
22373
22374            result = Some(pair);
22375        }
22376
22377        result
22378    };
22379    let Some(pair) = pair else {
22380        return false;
22381    };
22382    pair.newline_only
22383        && buffer
22384            .chars_for_range(pair.open_range.end..range.start)
22385            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22386            .all(|c| c.is_whitespace() && c != '\n')
22387}
22388
22389fn update_uncommitted_diff_for_buffer(
22390    editor: Entity<Editor>,
22391    project: &Entity<Project>,
22392    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22393    buffer: Entity<MultiBuffer>,
22394    cx: &mut App,
22395) -> Task<()> {
22396    let mut tasks = Vec::new();
22397    project.update(cx, |project, cx| {
22398        for buffer in buffers {
22399            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22400                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22401            }
22402        }
22403    });
22404    cx.spawn(async move |cx| {
22405        let diffs = future::join_all(tasks).await;
22406        if editor
22407            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22408            .unwrap_or(false)
22409        {
22410            return;
22411        }
22412
22413        buffer
22414            .update(cx, |buffer, cx| {
22415                for diff in diffs.into_iter().flatten() {
22416                    buffer.add_diff(diff, cx);
22417                }
22418            })
22419            .ok();
22420    })
22421}
22422
22423fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22424    let tab_size = tab_size.get() as usize;
22425    let mut width = offset;
22426
22427    for ch in text.chars() {
22428        width += if ch == '\t' {
22429            tab_size - (width % tab_size)
22430        } else {
22431            1
22432        };
22433    }
22434
22435    width - offset
22436}
22437
22438#[cfg(test)]
22439mod tests {
22440    use super::*;
22441
22442    #[test]
22443    fn test_string_size_with_expanded_tabs() {
22444        let nz = |val| NonZeroU32::new(val).unwrap();
22445        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22446        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22447        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22448        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22449        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22450        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22451        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22452        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22453    }
22454}
22455
22456/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22457struct WordBreakingTokenizer<'a> {
22458    input: &'a str,
22459}
22460
22461impl<'a> WordBreakingTokenizer<'a> {
22462    fn new(input: &'a str) -> Self {
22463        Self { input }
22464    }
22465}
22466
22467fn is_char_ideographic(ch: char) -> bool {
22468    use unicode_script::Script::*;
22469    use unicode_script::UnicodeScript;
22470    matches!(ch.script(), Han | Tangut | Yi)
22471}
22472
22473fn is_grapheme_ideographic(text: &str) -> bool {
22474    text.chars().any(is_char_ideographic)
22475}
22476
22477fn is_grapheme_whitespace(text: &str) -> bool {
22478    text.chars().any(|x| x.is_whitespace())
22479}
22480
22481fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22482    text.chars()
22483        .next()
22484        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22485}
22486
22487#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22488enum WordBreakToken<'a> {
22489    Word { token: &'a str, grapheme_len: usize },
22490    InlineWhitespace { token: &'a str, grapheme_len: usize },
22491    Newline,
22492}
22493
22494impl<'a> Iterator for WordBreakingTokenizer<'a> {
22495    /// Yields a span, the count of graphemes in the token, and whether it was
22496    /// whitespace. Note that it also breaks at word boundaries.
22497    type Item = WordBreakToken<'a>;
22498
22499    fn next(&mut self) -> Option<Self::Item> {
22500        use unicode_segmentation::UnicodeSegmentation;
22501        if self.input.is_empty() {
22502            return None;
22503        }
22504
22505        let mut iter = self.input.graphemes(true).peekable();
22506        let mut offset = 0;
22507        let mut grapheme_len = 0;
22508        if let Some(first_grapheme) = iter.next() {
22509            let is_newline = first_grapheme == "\n";
22510            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22511            offset += first_grapheme.len();
22512            grapheme_len += 1;
22513            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22514                if let Some(grapheme) = iter.peek().copied()
22515                    && should_stay_with_preceding_ideograph(grapheme)
22516                {
22517                    offset += grapheme.len();
22518                    grapheme_len += 1;
22519                }
22520            } else {
22521                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22522                let mut next_word_bound = words.peek().copied();
22523                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22524                    next_word_bound = words.next();
22525                }
22526                while let Some(grapheme) = iter.peek().copied() {
22527                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22528                        break;
22529                    };
22530                    if is_grapheme_whitespace(grapheme) != is_whitespace
22531                        || (grapheme == "\n") != is_newline
22532                    {
22533                        break;
22534                    };
22535                    offset += grapheme.len();
22536                    grapheme_len += 1;
22537                    iter.next();
22538                }
22539            }
22540            let token = &self.input[..offset];
22541            self.input = &self.input[offset..];
22542            if token == "\n" {
22543                Some(WordBreakToken::Newline)
22544            } else if is_whitespace {
22545                Some(WordBreakToken::InlineWhitespace {
22546                    token,
22547                    grapheme_len,
22548                })
22549            } else {
22550                Some(WordBreakToken::Word {
22551                    token,
22552                    grapheme_len,
22553                })
22554            }
22555        } else {
22556            None
22557        }
22558    }
22559}
22560
22561#[test]
22562fn test_word_breaking_tokenizer() {
22563    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22564        ("", &[]),
22565        ("  ", &[whitespace("  ", 2)]),
22566        ("Ʒ", &[word("Ʒ", 1)]),
22567        ("Ǽ", &[word("Ǽ", 1)]),
22568        ("", &[word("", 1)]),
22569        ("⋑⋑", &[word("⋑⋑", 2)]),
22570        (
22571            "原理,进而",
22572            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22573        ),
22574        (
22575            "hello world",
22576            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22577        ),
22578        (
22579            "hello, world",
22580            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22581        ),
22582        (
22583            "  hello world",
22584            &[
22585                whitespace("  ", 2),
22586                word("hello", 5),
22587                whitespace(" ", 1),
22588                word("world", 5),
22589            ],
22590        ),
22591        (
22592            "这是什么 \n 钢笔",
22593            &[
22594                word("", 1),
22595                word("", 1),
22596                word("", 1),
22597                word("", 1),
22598                whitespace(" ", 1),
22599                newline(),
22600                whitespace(" ", 1),
22601                word("", 1),
22602                word("", 1),
22603            ],
22604        ),
22605        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22606    ];
22607
22608    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22609        WordBreakToken::Word {
22610            token,
22611            grapheme_len,
22612        }
22613    }
22614
22615    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22616        WordBreakToken::InlineWhitespace {
22617            token,
22618            grapheme_len,
22619        }
22620    }
22621
22622    fn newline() -> WordBreakToken<'static> {
22623        WordBreakToken::Newline
22624    }
22625
22626    for (input, result) in tests {
22627        assert_eq!(
22628            WordBreakingTokenizer::new(input)
22629                .collect::<Vec<_>>()
22630                .as_slice(),
22631            *result,
22632        );
22633    }
22634}
22635
22636fn wrap_with_prefix(
22637    first_line_prefix: String,
22638    subsequent_lines_prefix: String,
22639    unwrapped_text: String,
22640    wrap_column: usize,
22641    tab_size: NonZeroU32,
22642    preserve_existing_whitespace: bool,
22643) -> String {
22644    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22645    let subsequent_lines_prefix_len =
22646        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22647    let mut wrapped_text = String::new();
22648    let mut current_line = first_line_prefix;
22649    let mut is_first_line = true;
22650
22651    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22652    let mut current_line_len = first_line_prefix_len;
22653    let mut in_whitespace = false;
22654    for token in tokenizer {
22655        let have_preceding_whitespace = in_whitespace;
22656        match token {
22657            WordBreakToken::Word {
22658                token,
22659                grapheme_len,
22660            } => {
22661                in_whitespace = false;
22662                let current_prefix_len = if is_first_line {
22663                    first_line_prefix_len
22664                } else {
22665                    subsequent_lines_prefix_len
22666                };
22667                if current_line_len + grapheme_len > wrap_column
22668                    && current_line_len != current_prefix_len
22669                {
22670                    wrapped_text.push_str(current_line.trim_end());
22671                    wrapped_text.push('\n');
22672                    is_first_line = false;
22673                    current_line = subsequent_lines_prefix.clone();
22674                    current_line_len = subsequent_lines_prefix_len;
22675                }
22676                current_line.push_str(token);
22677                current_line_len += grapheme_len;
22678            }
22679            WordBreakToken::InlineWhitespace {
22680                mut token,
22681                mut grapheme_len,
22682            } => {
22683                in_whitespace = true;
22684                if have_preceding_whitespace && !preserve_existing_whitespace {
22685                    continue;
22686                }
22687                if !preserve_existing_whitespace {
22688                    // Keep a single whitespace grapheme as-is
22689                    if let Some(first) =
22690                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22691                    {
22692                        token = first;
22693                    } else {
22694                        token = " ";
22695                    }
22696                    grapheme_len = 1;
22697                }
22698                let current_prefix_len = if is_first_line {
22699                    first_line_prefix_len
22700                } else {
22701                    subsequent_lines_prefix_len
22702                };
22703                if current_line_len + grapheme_len > wrap_column {
22704                    wrapped_text.push_str(current_line.trim_end());
22705                    wrapped_text.push('\n');
22706                    is_first_line = false;
22707                    current_line = subsequent_lines_prefix.clone();
22708                    current_line_len = subsequent_lines_prefix_len;
22709                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22710                    current_line.push_str(token);
22711                    current_line_len += grapheme_len;
22712                }
22713            }
22714            WordBreakToken::Newline => {
22715                in_whitespace = true;
22716                let current_prefix_len = if is_first_line {
22717                    first_line_prefix_len
22718                } else {
22719                    subsequent_lines_prefix_len
22720                };
22721                if preserve_existing_whitespace {
22722                    wrapped_text.push_str(current_line.trim_end());
22723                    wrapped_text.push('\n');
22724                    is_first_line = false;
22725                    current_line = subsequent_lines_prefix.clone();
22726                    current_line_len = subsequent_lines_prefix_len;
22727                } else if have_preceding_whitespace {
22728                    continue;
22729                } else if current_line_len + 1 > wrap_column
22730                    && current_line_len != current_prefix_len
22731                {
22732                    wrapped_text.push_str(current_line.trim_end());
22733                    wrapped_text.push('\n');
22734                    is_first_line = false;
22735                    current_line = subsequent_lines_prefix.clone();
22736                    current_line_len = subsequent_lines_prefix_len;
22737                } else if current_line_len != current_prefix_len {
22738                    current_line.push(' ');
22739                    current_line_len += 1;
22740                }
22741            }
22742        }
22743    }
22744
22745    if !current_line.is_empty() {
22746        wrapped_text.push_str(&current_line);
22747    }
22748    wrapped_text
22749}
22750
22751#[test]
22752fn test_wrap_with_prefix() {
22753    assert_eq!(
22754        wrap_with_prefix(
22755            "# ".to_string(),
22756            "# ".to_string(),
22757            "abcdefg".to_string(),
22758            4,
22759            NonZeroU32::new(4).unwrap(),
22760            false,
22761        ),
22762        "# abcdefg"
22763    );
22764    assert_eq!(
22765        wrap_with_prefix(
22766            "".to_string(),
22767            "".to_string(),
22768            "\thello world".to_string(),
22769            8,
22770            NonZeroU32::new(4).unwrap(),
22771            false,
22772        ),
22773        "hello\nworld"
22774    );
22775    assert_eq!(
22776        wrap_with_prefix(
22777            "// ".to_string(),
22778            "// ".to_string(),
22779            "xx \nyy zz aa bb cc".to_string(),
22780            12,
22781            NonZeroU32::new(4).unwrap(),
22782            false,
22783        ),
22784        "// xx yy zz\n// aa bb cc"
22785    );
22786    assert_eq!(
22787        wrap_with_prefix(
22788            String::new(),
22789            String::new(),
22790            "这是什么 \n 钢笔".to_string(),
22791            3,
22792            NonZeroU32::new(4).unwrap(),
22793            false,
22794        ),
22795        "这是什\n么 钢\n"
22796    );
22797    assert_eq!(
22798        wrap_with_prefix(
22799            String::new(),
22800            String::new(),
22801            format!("foo{}bar", '\u{2009}'), // thin space
22802            80,
22803            NonZeroU32::new(4).unwrap(),
22804            false,
22805        ),
22806        format!("foo{}bar", '\u{2009}')
22807    );
22808}
22809
22810pub trait CollaborationHub {
22811    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22812    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22813    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22814}
22815
22816impl CollaborationHub for Entity<Project> {
22817    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22818        self.read(cx).collaborators()
22819    }
22820
22821    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22822        self.read(cx).user_store().read(cx).participant_indices()
22823    }
22824
22825    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22826        let this = self.read(cx);
22827        let user_ids = this.collaborators().values().map(|c| c.user_id);
22828        this.user_store().read(cx).participant_names(user_ids, cx)
22829    }
22830}
22831
22832pub trait SemanticsProvider {
22833    fn hover(
22834        &self,
22835        buffer: &Entity<Buffer>,
22836        position: text::Anchor,
22837        cx: &mut App,
22838    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22839
22840    fn inline_values(
22841        &self,
22842        buffer_handle: Entity<Buffer>,
22843        range: Range<text::Anchor>,
22844        cx: &mut App,
22845    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22846
22847    fn inlay_hints(
22848        &self,
22849        buffer_handle: Entity<Buffer>,
22850        range: Range<text::Anchor>,
22851        cx: &mut App,
22852    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22853
22854    fn resolve_inlay_hint(
22855        &self,
22856        hint: InlayHint,
22857        buffer_handle: Entity<Buffer>,
22858        server_id: LanguageServerId,
22859        cx: &mut App,
22860    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22861
22862    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22863
22864    fn document_highlights(
22865        &self,
22866        buffer: &Entity<Buffer>,
22867        position: text::Anchor,
22868        cx: &mut App,
22869    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22870
22871    fn definitions(
22872        &self,
22873        buffer: &Entity<Buffer>,
22874        position: text::Anchor,
22875        kind: GotoDefinitionKind,
22876        cx: &mut App,
22877    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22878
22879    fn range_for_rename(
22880        &self,
22881        buffer: &Entity<Buffer>,
22882        position: text::Anchor,
22883        cx: &mut App,
22884    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22885
22886    fn perform_rename(
22887        &self,
22888        buffer: &Entity<Buffer>,
22889        position: text::Anchor,
22890        new_name: String,
22891        cx: &mut App,
22892    ) -> Option<Task<Result<ProjectTransaction>>>;
22893}
22894
22895pub trait CompletionProvider {
22896    fn completions(
22897        &self,
22898        excerpt_id: ExcerptId,
22899        buffer: &Entity<Buffer>,
22900        buffer_position: text::Anchor,
22901        trigger: CompletionContext,
22902        window: &mut Window,
22903        cx: &mut Context<Editor>,
22904    ) -> Task<Result<Vec<CompletionResponse>>>;
22905
22906    fn resolve_completions(
22907        &self,
22908        _buffer: Entity<Buffer>,
22909        _completion_indices: Vec<usize>,
22910        _completions: Rc<RefCell<Box<[Completion]>>>,
22911        _cx: &mut Context<Editor>,
22912    ) -> Task<Result<bool>> {
22913        Task::ready(Ok(false))
22914    }
22915
22916    fn apply_additional_edits_for_completion(
22917        &self,
22918        _buffer: Entity<Buffer>,
22919        _completions: Rc<RefCell<Box<[Completion]>>>,
22920        _completion_index: usize,
22921        _push_to_history: bool,
22922        _cx: &mut Context<Editor>,
22923    ) -> Task<Result<Option<language::Transaction>>> {
22924        Task::ready(Ok(None))
22925    }
22926
22927    fn is_completion_trigger(
22928        &self,
22929        buffer: &Entity<Buffer>,
22930        position: language::Anchor,
22931        text: &str,
22932        trigger_in_words: bool,
22933        menu_is_open: bool,
22934        cx: &mut Context<Editor>,
22935    ) -> bool;
22936
22937    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22938
22939    fn sort_completions(&self) -> bool {
22940        true
22941    }
22942
22943    fn filter_completions(&self) -> bool {
22944        true
22945    }
22946}
22947
22948pub trait CodeActionProvider {
22949    fn id(&self) -> Arc<str>;
22950
22951    fn code_actions(
22952        &self,
22953        buffer: &Entity<Buffer>,
22954        range: Range<text::Anchor>,
22955        window: &mut Window,
22956        cx: &mut App,
22957    ) -> Task<Result<Vec<CodeAction>>>;
22958
22959    fn apply_code_action(
22960        &self,
22961        buffer_handle: Entity<Buffer>,
22962        action: CodeAction,
22963        excerpt_id: ExcerptId,
22964        push_to_history: bool,
22965        window: &mut Window,
22966        cx: &mut App,
22967    ) -> Task<Result<ProjectTransaction>>;
22968}
22969
22970impl CodeActionProvider for Entity<Project> {
22971    fn id(&self) -> Arc<str> {
22972        "project".into()
22973    }
22974
22975    fn code_actions(
22976        &self,
22977        buffer: &Entity<Buffer>,
22978        range: Range<text::Anchor>,
22979        _window: &mut Window,
22980        cx: &mut App,
22981    ) -> Task<Result<Vec<CodeAction>>> {
22982        self.update(cx, |project, cx| {
22983            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22984            let code_actions = project.code_actions(buffer, range, None, cx);
22985            cx.background_spawn(async move {
22986                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22987                Ok(code_lens_actions
22988                    .context("code lens fetch")?
22989                    .into_iter()
22990                    .flatten()
22991                    .chain(
22992                        code_actions
22993                            .context("code action fetch")?
22994                            .into_iter()
22995                            .flatten(),
22996                    )
22997                    .collect())
22998            })
22999        })
23000    }
23001
23002    fn apply_code_action(
23003        &self,
23004        buffer_handle: Entity<Buffer>,
23005        action: CodeAction,
23006        _excerpt_id: ExcerptId,
23007        push_to_history: bool,
23008        _window: &mut Window,
23009        cx: &mut App,
23010    ) -> Task<Result<ProjectTransaction>> {
23011        self.update(cx, |project, cx| {
23012            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23013        })
23014    }
23015}
23016
23017fn snippet_completions(
23018    project: &Project,
23019    buffer: &Entity<Buffer>,
23020    buffer_position: text::Anchor,
23021    cx: &mut App,
23022) -> Task<Result<CompletionResponse>> {
23023    let languages = buffer.read(cx).languages_at(buffer_position);
23024    let snippet_store = project.snippets().read(cx);
23025
23026    let scopes: Vec<_> = languages
23027        .iter()
23028        .filter_map(|language| {
23029            let language_name = language.lsp_id();
23030            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23031
23032            if snippets.is_empty() {
23033                None
23034            } else {
23035                Some((language.default_scope(), snippets))
23036            }
23037        })
23038        .collect();
23039
23040    if scopes.is_empty() {
23041        return Task::ready(Ok(CompletionResponse {
23042            completions: vec![],
23043            display_options: CompletionDisplayOptions::default(),
23044            is_incomplete: false,
23045        }));
23046    }
23047
23048    let snapshot = buffer.read(cx).text_snapshot();
23049    let executor = cx.background_executor().clone();
23050
23051    cx.background_spawn(async move {
23052        let mut is_incomplete = false;
23053        let mut completions: Vec<Completion> = Vec::new();
23054        for (scope, snippets) in scopes.into_iter() {
23055            let classifier =
23056                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23057
23058            const MAX_WORD_PREFIX_LEN: usize = 128;
23059            let last_word: String = snapshot
23060                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23061                .take(MAX_WORD_PREFIX_LEN)
23062                .take_while(|c| classifier.is_word(*c))
23063                .collect::<String>()
23064                .chars()
23065                .rev()
23066                .collect();
23067
23068            if last_word.is_empty() {
23069                return Ok(CompletionResponse {
23070                    completions: vec![],
23071                    display_options: CompletionDisplayOptions::default(),
23072                    is_incomplete: true,
23073                });
23074            }
23075
23076            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23077            let to_lsp = |point: &text::Anchor| {
23078                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23079                point_to_lsp(end)
23080            };
23081            let lsp_end = to_lsp(&buffer_position);
23082
23083            let candidates = snippets
23084                .iter()
23085                .enumerate()
23086                .flat_map(|(ix, snippet)| {
23087                    snippet
23088                        .prefix
23089                        .iter()
23090                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23091                })
23092                .collect::<Vec<StringMatchCandidate>>();
23093
23094            const MAX_RESULTS: usize = 100;
23095            let mut matches = fuzzy::match_strings(
23096                &candidates,
23097                &last_word,
23098                last_word.chars().any(|c| c.is_uppercase()),
23099                true,
23100                MAX_RESULTS,
23101                &Default::default(),
23102                executor.clone(),
23103            )
23104            .await;
23105
23106            if matches.len() >= MAX_RESULTS {
23107                is_incomplete = true;
23108            }
23109
23110            // Remove all candidates where the query's start does not match the start of any word in the candidate
23111            if let Some(query_start) = last_word.chars().next() {
23112                matches.retain(|string_match| {
23113                    split_words(&string_match.string).any(|word| {
23114                        // Check that the first codepoint of the word as lowercase matches the first
23115                        // codepoint of the query as lowercase
23116                        word.chars()
23117                            .flat_map(|codepoint| codepoint.to_lowercase())
23118                            .zip(query_start.to_lowercase())
23119                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23120                    })
23121                });
23122            }
23123
23124            let matched_strings = matches
23125                .into_iter()
23126                .map(|m| m.string)
23127                .collect::<HashSet<_>>();
23128
23129            completions.extend(snippets.iter().filter_map(|snippet| {
23130                let matching_prefix = snippet
23131                    .prefix
23132                    .iter()
23133                    .find(|prefix| matched_strings.contains(*prefix))?;
23134                let start = as_offset - last_word.len();
23135                let start = snapshot.anchor_before(start);
23136                let range = start..buffer_position;
23137                let lsp_start = to_lsp(&start);
23138                let lsp_range = lsp::Range {
23139                    start: lsp_start,
23140                    end: lsp_end,
23141                };
23142                Some(Completion {
23143                    replace_range: range,
23144                    new_text: snippet.body.clone(),
23145                    source: CompletionSource::Lsp {
23146                        insert_range: None,
23147                        server_id: LanguageServerId(usize::MAX),
23148                        resolved: true,
23149                        lsp_completion: Box::new(lsp::CompletionItem {
23150                            label: snippet.prefix.first().unwrap().clone(),
23151                            kind: Some(CompletionItemKind::SNIPPET),
23152                            label_details: snippet.description.as_ref().map(|description| {
23153                                lsp::CompletionItemLabelDetails {
23154                                    detail: Some(description.clone()),
23155                                    description: None,
23156                                }
23157                            }),
23158                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23159                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23160                                lsp::InsertReplaceEdit {
23161                                    new_text: snippet.body.clone(),
23162                                    insert: lsp_range,
23163                                    replace: lsp_range,
23164                                },
23165                            )),
23166                            filter_text: Some(snippet.body.clone()),
23167                            sort_text: Some(char::MAX.to_string()),
23168                            ..lsp::CompletionItem::default()
23169                        }),
23170                        lsp_defaults: None,
23171                    },
23172                    label: CodeLabel::plain(matching_prefix.clone(), None),
23173                    icon_path: None,
23174                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23175                        single_line: snippet.name.clone().into(),
23176                        plain_text: snippet
23177                            .description
23178                            .clone()
23179                            .map(|description| description.into()),
23180                    }),
23181                    insert_text_mode: None,
23182                    confirm: None,
23183                })
23184            }))
23185        }
23186
23187        Ok(CompletionResponse {
23188            completions,
23189            display_options: CompletionDisplayOptions::default(),
23190            is_incomplete,
23191        })
23192    })
23193}
23194
23195impl CompletionProvider for Entity<Project> {
23196    fn completions(
23197        &self,
23198        _excerpt_id: ExcerptId,
23199        buffer: &Entity<Buffer>,
23200        buffer_position: text::Anchor,
23201        options: CompletionContext,
23202        _window: &mut Window,
23203        cx: &mut Context<Editor>,
23204    ) -> Task<Result<Vec<CompletionResponse>>> {
23205        self.update(cx, |project, cx| {
23206            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23207            let project_completions = project.completions(buffer, buffer_position, options, cx);
23208            cx.background_spawn(async move {
23209                let mut responses = project_completions.await?;
23210                let snippets = snippets.await?;
23211                if !snippets.completions.is_empty() {
23212                    responses.push(snippets);
23213                }
23214                Ok(responses)
23215            })
23216        })
23217    }
23218
23219    fn resolve_completions(
23220        &self,
23221        buffer: Entity<Buffer>,
23222        completion_indices: Vec<usize>,
23223        completions: Rc<RefCell<Box<[Completion]>>>,
23224        cx: &mut Context<Editor>,
23225    ) -> Task<Result<bool>> {
23226        self.update(cx, |project, cx| {
23227            project.lsp_store().update(cx, |lsp_store, cx| {
23228                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23229            })
23230        })
23231    }
23232
23233    fn apply_additional_edits_for_completion(
23234        &self,
23235        buffer: Entity<Buffer>,
23236        completions: Rc<RefCell<Box<[Completion]>>>,
23237        completion_index: usize,
23238        push_to_history: bool,
23239        cx: &mut Context<Editor>,
23240    ) -> Task<Result<Option<language::Transaction>>> {
23241        self.update(cx, |project, cx| {
23242            project.lsp_store().update(cx, |lsp_store, cx| {
23243                lsp_store.apply_additional_edits_for_completion(
23244                    buffer,
23245                    completions,
23246                    completion_index,
23247                    push_to_history,
23248                    cx,
23249                )
23250            })
23251        })
23252    }
23253
23254    fn is_completion_trigger(
23255        &self,
23256        buffer: &Entity<Buffer>,
23257        position: language::Anchor,
23258        text: &str,
23259        trigger_in_words: bool,
23260        menu_is_open: bool,
23261        cx: &mut Context<Editor>,
23262    ) -> bool {
23263        let mut chars = text.chars();
23264        let char = if let Some(char) = chars.next() {
23265            char
23266        } else {
23267            return false;
23268        };
23269        if chars.next().is_some() {
23270            return false;
23271        }
23272
23273        let buffer = buffer.read(cx);
23274        let snapshot = buffer.snapshot();
23275        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23276            return false;
23277        }
23278        let classifier = snapshot
23279            .char_classifier_at(position)
23280            .scope_context(Some(CharScopeContext::Completion));
23281        if trigger_in_words && classifier.is_word(char) {
23282            return true;
23283        }
23284
23285        buffer.completion_triggers().contains(text)
23286    }
23287}
23288
23289impl SemanticsProvider for Entity<Project> {
23290    fn hover(
23291        &self,
23292        buffer: &Entity<Buffer>,
23293        position: text::Anchor,
23294        cx: &mut App,
23295    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23296        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23297    }
23298
23299    fn document_highlights(
23300        &self,
23301        buffer: &Entity<Buffer>,
23302        position: text::Anchor,
23303        cx: &mut App,
23304    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23305        Some(self.update(cx, |project, cx| {
23306            project.document_highlights(buffer, position, cx)
23307        }))
23308    }
23309
23310    fn definitions(
23311        &self,
23312        buffer: &Entity<Buffer>,
23313        position: text::Anchor,
23314        kind: GotoDefinitionKind,
23315        cx: &mut App,
23316    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23317        Some(self.update(cx, |project, cx| match kind {
23318            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23319            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23320            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23321            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23322        }))
23323    }
23324
23325    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23326        self.update(cx, |project, cx| {
23327            if project
23328                .active_debug_session(cx)
23329                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23330            {
23331                return true;
23332            }
23333
23334            buffer.update(cx, |buffer, cx| {
23335                project.any_language_server_supports_inlay_hints(buffer, cx)
23336            })
23337        })
23338    }
23339
23340    fn inline_values(
23341        &self,
23342        buffer_handle: Entity<Buffer>,
23343        range: Range<text::Anchor>,
23344        cx: &mut App,
23345    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23346        self.update(cx, |project, cx| {
23347            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23348
23349            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23350        })
23351    }
23352
23353    fn inlay_hints(
23354        &self,
23355        buffer_handle: Entity<Buffer>,
23356        range: Range<text::Anchor>,
23357        cx: &mut App,
23358    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23359        Some(self.update(cx, |project, cx| {
23360            project.inlay_hints(buffer_handle, range, cx)
23361        }))
23362    }
23363
23364    fn resolve_inlay_hint(
23365        &self,
23366        hint: InlayHint,
23367        buffer_handle: Entity<Buffer>,
23368        server_id: LanguageServerId,
23369        cx: &mut App,
23370    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23371        Some(self.update(cx, |project, cx| {
23372            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23373        }))
23374    }
23375
23376    fn range_for_rename(
23377        &self,
23378        buffer: &Entity<Buffer>,
23379        position: text::Anchor,
23380        cx: &mut App,
23381    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23382        Some(self.update(cx, |project, cx| {
23383            let buffer = buffer.clone();
23384            let task = project.prepare_rename(buffer.clone(), position, cx);
23385            cx.spawn(async move |_, cx| {
23386                Ok(match task.await? {
23387                    PrepareRenameResponse::Success(range) => Some(range),
23388                    PrepareRenameResponse::InvalidPosition => None,
23389                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23390                        // Fallback on using TreeSitter info to determine identifier range
23391                        buffer.read_with(cx, |buffer, _| {
23392                            let snapshot = buffer.snapshot();
23393                            let (range, kind) = snapshot.surrounding_word(position, None);
23394                            if kind != Some(CharKind::Word) {
23395                                return None;
23396                            }
23397                            Some(
23398                                snapshot.anchor_before(range.start)
23399                                    ..snapshot.anchor_after(range.end),
23400                            )
23401                        })?
23402                    }
23403                })
23404            })
23405        }))
23406    }
23407
23408    fn perform_rename(
23409        &self,
23410        buffer: &Entity<Buffer>,
23411        position: text::Anchor,
23412        new_name: String,
23413        cx: &mut App,
23414    ) -> Option<Task<Result<ProjectTransaction>>> {
23415        Some(self.update(cx, |project, cx| {
23416            project.perform_rename(buffer.clone(), position, new_name, cx)
23417        }))
23418    }
23419}
23420
23421fn inlay_hint_settings(
23422    location: Anchor,
23423    snapshot: &MultiBufferSnapshot,
23424    cx: &mut Context<Editor>,
23425) -> InlayHintSettings {
23426    let file = snapshot.file_at(location);
23427    let language = snapshot.language_at(location).map(|l| l.name());
23428    language_settings(language, file, cx).inlay_hints
23429}
23430
23431fn consume_contiguous_rows(
23432    contiguous_row_selections: &mut Vec<Selection<Point>>,
23433    selection: &Selection<Point>,
23434    display_map: &DisplaySnapshot,
23435    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23436) -> (MultiBufferRow, MultiBufferRow) {
23437    contiguous_row_selections.push(selection.clone());
23438    let start_row = starting_row(selection, display_map);
23439    let mut end_row = ending_row(selection, display_map);
23440
23441    while let Some(next_selection) = selections.peek() {
23442        if next_selection.start.row <= end_row.0 {
23443            end_row = ending_row(next_selection, display_map);
23444            contiguous_row_selections.push(selections.next().unwrap().clone());
23445        } else {
23446            break;
23447        }
23448    }
23449    (start_row, end_row)
23450}
23451
23452fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23453    if selection.start.column > 0 {
23454        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23455    } else {
23456        MultiBufferRow(selection.start.row)
23457    }
23458}
23459
23460fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23461    if next_selection.end.column > 0 || next_selection.is_empty() {
23462        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23463    } else {
23464        MultiBufferRow(next_selection.end.row)
23465    }
23466}
23467
23468impl EditorSnapshot {
23469    pub fn remote_selections_in_range<'a>(
23470        &'a self,
23471        range: &'a Range<Anchor>,
23472        collaboration_hub: &dyn CollaborationHub,
23473        cx: &'a App,
23474    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23475        let participant_names = collaboration_hub.user_names(cx);
23476        let participant_indices = collaboration_hub.user_participant_indices(cx);
23477        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23478        let collaborators_by_replica_id = collaborators_by_peer_id
23479            .values()
23480            .map(|collaborator| (collaborator.replica_id, collaborator))
23481            .collect::<HashMap<_, _>>();
23482        self.buffer_snapshot()
23483            .selections_in_range(range, false)
23484            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23485                if replica_id == AGENT_REPLICA_ID {
23486                    Some(RemoteSelection {
23487                        replica_id,
23488                        selection,
23489                        cursor_shape,
23490                        line_mode,
23491                        collaborator_id: CollaboratorId::Agent,
23492                        user_name: Some("Agent".into()),
23493                        color: cx.theme().players().agent(),
23494                    })
23495                } else {
23496                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23497                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23498                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23499                    Some(RemoteSelection {
23500                        replica_id,
23501                        selection,
23502                        cursor_shape,
23503                        line_mode,
23504                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23505                        user_name,
23506                        color: if let Some(index) = participant_index {
23507                            cx.theme().players().color_for_participant(index.0)
23508                        } else {
23509                            cx.theme().players().absent()
23510                        },
23511                    })
23512                }
23513            })
23514    }
23515
23516    pub fn hunks_for_ranges(
23517        &self,
23518        ranges: impl IntoIterator<Item = Range<Point>>,
23519    ) -> Vec<MultiBufferDiffHunk> {
23520        let mut hunks = Vec::new();
23521        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23522            HashMap::default();
23523        for query_range in ranges {
23524            let query_rows =
23525                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23526            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23527                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23528            ) {
23529                // Include deleted hunks that are adjacent to the query range, because
23530                // otherwise they would be missed.
23531                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23532                if hunk.status().is_deleted() {
23533                    intersects_range |= hunk.row_range.start == query_rows.end;
23534                    intersects_range |= hunk.row_range.end == query_rows.start;
23535                }
23536                if intersects_range {
23537                    if !processed_buffer_rows
23538                        .entry(hunk.buffer_id)
23539                        .or_default()
23540                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23541                    {
23542                        continue;
23543                    }
23544                    hunks.push(hunk);
23545                }
23546            }
23547        }
23548
23549        hunks
23550    }
23551
23552    fn display_diff_hunks_for_rows<'a>(
23553        &'a self,
23554        display_rows: Range<DisplayRow>,
23555        folded_buffers: &'a HashSet<BufferId>,
23556    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23557        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23558        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23559
23560        self.buffer_snapshot()
23561            .diff_hunks_in_range(buffer_start..buffer_end)
23562            .filter_map(|hunk| {
23563                if folded_buffers.contains(&hunk.buffer_id) {
23564                    return None;
23565                }
23566
23567                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23568                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23569
23570                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23571                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23572
23573                let display_hunk = if hunk_display_start.column() != 0 {
23574                    DisplayDiffHunk::Folded {
23575                        display_row: hunk_display_start.row(),
23576                    }
23577                } else {
23578                    let mut end_row = hunk_display_end.row();
23579                    if hunk_display_end.column() > 0 {
23580                        end_row.0 += 1;
23581                    }
23582                    let is_created_file = hunk.is_created_file();
23583                    DisplayDiffHunk::Unfolded {
23584                        status: hunk.status(),
23585                        diff_base_byte_range: hunk.diff_base_byte_range,
23586                        display_row_range: hunk_display_start.row()..end_row,
23587                        multi_buffer_range: Anchor::range_in_buffer(
23588                            hunk.excerpt_id,
23589                            hunk.buffer_id,
23590                            hunk.buffer_range,
23591                        ),
23592                        is_created_file,
23593                    }
23594                };
23595
23596                Some(display_hunk)
23597            })
23598    }
23599
23600    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23601        self.display_snapshot
23602            .buffer_snapshot()
23603            .language_at(position)
23604    }
23605
23606    pub fn is_focused(&self) -> bool {
23607        self.is_focused
23608    }
23609
23610    pub fn placeholder_text(&self) -> Option<String> {
23611        self.placeholder_display_snapshot
23612            .as_ref()
23613            .map(|display_map| display_map.text())
23614    }
23615
23616    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23617        self.scroll_anchor.scroll_position(&self.display_snapshot)
23618    }
23619
23620    fn gutter_dimensions(
23621        &self,
23622        font_id: FontId,
23623        font_size: Pixels,
23624        max_line_number_width: Pixels,
23625        cx: &App,
23626    ) -> Option<GutterDimensions> {
23627        if !self.show_gutter {
23628            return None;
23629        }
23630
23631        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23632        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23633
23634        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23635            matches!(
23636                ProjectSettings::get_global(cx).git.git_gutter,
23637                GitGutterSetting::TrackedFiles
23638            )
23639        });
23640        let gutter_settings = EditorSettings::get_global(cx).gutter;
23641        let show_line_numbers = self
23642            .show_line_numbers
23643            .unwrap_or(gutter_settings.line_numbers);
23644        let line_gutter_width = if show_line_numbers {
23645            // Avoid flicker-like gutter resizes when the line number gains another digit by
23646            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23647            let min_width_for_number_on_gutter =
23648                ch_advance * gutter_settings.min_line_number_digits as f32;
23649            max_line_number_width.max(min_width_for_number_on_gutter)
23650        } else {
23651            0.0.into()
23652        };
23653
23654        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23655        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23656
23657        let git_blame_entries_width =
23658            self.git_blame_gutter_max_author_length
23659                .map(|max_author_length| {
23660                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23661                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23662
23663                    /// The number of characters to dedicate to gaps and margins.
23664                    const SPACING_WIDTH: usize = 4;
23665
23666                    let max_char_count = max_author_length.min(renderer.max_author_length())
23667                        + ::git::SHORT_SHA_LENGTH
23668                        + MAX_RELATIVE_TIMESTAMP.len()
23669                        + SPACING_WIDTH;
23670
23671                    ch_advance * max_char_count
23672                });
23673
23674        let is_singleton = self.buffer_snapshot().is_singleton();
23675
23676        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23677        left_padding += if !is_singleton {
23678            ch_width * 4.0
23679        } else if show_runnables || show_breakpoints {
23680            ch_width * 3.0
23681        } else if show_git_gutter && show_line_numbers {
23682            ch_width * 2.0
23683        } else if show_git_gutter || show_line_numbers {
23684            ch_width
23685        } else {
23686            px(0.)
23687        };
23688
23689        let shows_folds = is_singleton && gutter_settings.folds;
23690
23691        let right_padding = if shows_folds && show_line_numbers {
23692            ch_width * 4.0
23693        } else if shows_folds || (!is_singleton && show_line_numbers) {
23694            ch_width * 3.0
23695        } else if show_line_numbers {
23696            ch_width
23697        } else {
23698            px(0.)
23699        };
23700
23701        Some(GutterDimensions {
23702            left_padding,
23703            right_padding,
23704            width: line_gutter_width + left_padding + right_padding,
23705            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23706            git_blame_entries_width,
23707        })
23708    }
23709
23710    pub fn render_crease_toggle(
23711        &self,
23712        buffer_row: MultiBufferRow,
23713        row_contains_cursor: bool,
23714        editor: Entity<Editor>,
23715        window: &mut Window,
23716        cx: &mut App,
23717    ) -> Option<AnyElement> {
23718        let folded = self.is_line_folded(buffer_row);
23719        let mut is_foldable = false;
23720
23721        if let Some(crease) = self
23722            .crease_snapshot
23723            .query_row(buffer_row, self.buffer_snapshot())
23724        {
23725            is_foldable = true;
23726            match crease {
23727                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23728                    if let Some(render_toggle) = render_toggle {
23729                        let toggle_callback =
23730                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23731                                if folded {
23732                                    editor.update(cx, |editor, cx| {
23733                                        editor.fold_at(buffer_row, window, cx)
23734                                    });
23735                                } else {
23736                                    editor.update(cx, |editor, cx| {
23737                                        editor.unfold_at(buffer_row, window, cx)
23738                                    });
23739                                }
23740                            });
23741                        return Some((render_toggle)(
23742                            buffer_row,
23743                            folded,
23744                            toggle_callback,
23745                            window,
23746                            cx,
23747                        ));
23748                    }
23749                }
23750            }
23751        }
23752
23753        is_foldable |= self.starts_indent(buffer_row);
23754
23755        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23756            Some(
23757                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23758                    .toggle_state(folded)
23759                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23760                        if folded {
23761                            this.unfold_at(buffer_row, window, cx);
23762                        } else {
23763                            this.fold_at(buffer_row, window, cx);
23764                        }
23765                    }))
23766                    .into_any_element(),
23767            )
23768        } else {
23769            None
23770        }
23771    }
23772
23773    pub fn render_crease_trailer(
23774        &self,
23775        buffer_row: MultiBufferRow,
23776        window: &mut Window,
23777        cx: &mut App,
23778    ) -> Option<AnyElement> {
23779        let folded = self.is_line_folded(buffer_row);
23780        if let Crease::Inline { render_trailer, .. } = self
23781            .crease_snapshot
23782            .query_row(buffer_row, self.buffer_snapshot())?
23783        {
23784            let render_trailer = render_trailer.as_ref()?;
23785            Some(render_trailer(buffer_row, folded, window, cx))
23786        } else {
23787            None
23788        }
23789    }
23790}
23791
23792impl Deref for EditorSnapshot {
23793    type Target = DisplaySnapshot;
23794
23795    fn deref(&self) -> &Self::Target {
23796        &self.display_snapshot
23797    }
23798}
23799
23800#[derive(Clone, Debug, PartialEq, Eq)]
23801pub enum EditorEvent {
23802    InputIgnored {
23803        text: Arc<str>,
23804    },
23805    InputHandled {
23806        utf16_range_to_replace: Option<Range<isize>>,
23807        text: Arc<str>,
23808    },
23809    ExcerptsAdded {
23810        buffer: Entity<Buffer>,
23811        predecessor: ExcerptId,
23812        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23813    },
23814    ExcerptsRemoved {
23815        ids: Vec<ExcerptId>,
23816        removed_buffer_ids: Vec<BufferId>,
23817    },
23818    BufferFoldToggled {
23819        ids: Vec<ExcerptId>,
23820        folded: bool,
23821    },
23822    ExcerptsEdited {
23823        ids: Vec<ExcerptId>,
23824    },
23825    ExcerptsExpanded {
23826        ids: Vec<ExcerptId>,
23827    },
23828    BufferEdited,
23829    Edited {
23830        transaction_id: clock::Lamport,
23831    },
23832    Reparsed(BufferId),
23833    Focused,
23834    FocusedIn,
23835    Blurred,
23836    DirtyChanged,
23837    Saved,
23838    TitleChanged,
23839    SelectionsChanged {
23840        local: bool,
23841    },
23842    ScrollPositionChanged {
23843        local: bool,
23844        autoscroll: bool,
23845    },
23846    TransactionUndone {
23847        transaction_id: clock::Lamport,
23848    },
23849    TransactionBegun {
23850        transaction_id: clock::Lamport,
23851    },
23852    CursorShapeChanged,
23853    BreadcrumbsChanged,
23854    PushedToNavHistory {
23855        anchor: Anchor,
23856        is_deactivate: bool,
23857    },
23858}
23859
23860impl EventEmitter<EditorEvent> for Editor {}
23861
23862impl Focusable for Editor {
23863    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23864        self.focus_handle.clone()
23865    }
23866}
23867
23868impl Render for Editor {
23869    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23870        let settings = ThemeSettings::get_global(cx);
23871
23872        let mut text_style = match self.mode {
23873            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23874                color: cx.theme().colors().editor_foreground,
23875                font_family: settings.ui_font.family.clone(),
23876                font_features: settings.ui_font.features.clone(),
23877                font_fallbacks: settings.ui_font.fallbacks.clone(),
23878                font_size: rems(0.875).into(),
23879                font_weight: settings.ui_font.weight,
23880                line_height: relative(settings.buffer_line_height.value()),
23881                ..Default::default()
23882            },
23883            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23884                color: cx.theme().colors().editor_foreground,
23885                font_family: settings.buffer_font.family.clone(),
23886                font_features: settings.buffer_font.features.clone(),
23887                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23888                font_size: settings.buffer_font_size(cx).into(),
23889                font_weight: settings.buffer_font.weight,
23890                line_height: relative(settings.buffer_line_height.value()),
23891                ..Default::default()
23892            },
23893        };
23894        if let Some(text_style_refinement) = &self.text_style_refinement {
23895            text_style.refine(text_style_refinement)
23896        }
23897
23898        let background = match self.mode {
23899            EditorMode::SingleLine => cx.theme().system().transparent,
23900            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23901            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23902            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23903        };
23904
23905        EditorElement::new(
23906            &cx.entity(),
23907            EditorStyle {
23908                background,
23909                border: cx.theme().colors().border,
23910                local_player: cx.theme().players().local(),
23911                text: text_style,
23912                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23913                syntax: cx.theme().syntax().clone(),
23914                status: cx.theme().status().clone(),
23915                inlay_hints_style: make_inlay_hints_style(cx),
23916                edit_prediction_styles: make_suggestion_styles(cx),
23917                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23918                show_underlines: self.diagnostics_enabled(),
23919            },
23920        )
23921    }
23922}
23923
23924impl EntityInputHandler for Editor {
23925    fn text_for_range(
23926        &mut self,
23927        range_utf16: Range<usize>,
23928        adjusted_range: &mut Option<Range<usize>>,
23929        _: &mut Window,
23930        cx: &mut Context<Self>,
23931    ) -> Option<String> {
23932        let snapshot = self.buffer.read(cx).read(cx);
23933        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23934        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23935        if (start.0..end.0) != range_utf16 {
23936            adjusted_range.replace(start.0..end.0);
23937        }
23938        Some(snapshot.text_for_range(start..end).collect())
23939    }
23940
23941    fn selected_text_range(
23942        &mut self,
23943        ignore_disabled_input: bool,
23944        _: &mut Window,
23945        cx: &mut Context<Self>,
23946    ) -> Option<UTF16Selection> {
23947        // Prevent the IME menu from appearing when holding down an alphabetic key
23948        // while input is disabled.
23949        if !ignore_disabled_input && !self.input_enabled {
23950            return None;
23951        }
23952
23953        let selection = self
23954            .selections
23955            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23956        let range = selection.range();
23957
23958        Some(UTF16Selection {
23959            range: range.start.0..range.end.0,
23960            reversed: selection.reversed,
23961        })
23962    }
23963
23964    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23965        let snapshot = self.buffer.read(cx).read(cx);
23966        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23967        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23968    }
23969
23970    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23971        self.clear_highlights::<InputComposition>(cx);
23972        self.ime_transaction.take();
23973    }
23974
23975    fn replace_text_in_range(
23976        &mut self,
23977        range_utf16: Option<Range<usize>>,
23978        text: &str,
23979        window: &mut Window,
23980        cx: &mut Context<Self>,
23981    ) {
23982        if !self.input_enabled {
23983            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23984            return;
23985        }
23986
23987        self.transact(window, cx, |this, window, cx| {
23988            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23989                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23990                Some(this.selection_replacement_ranges(range_utf16, cx))
23991            } else {
23992                this.marked_text_ranges(cx)
23993            };
23994
23995            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23996                let newest_selection_id = this.selections.newest_anchor().id;
23997                this.selections
23998                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23999                    .iter()
24000                    .zip(ranges_to_replace.iter())
24001                    .find_map(|(selection, range)| {
24002                        if selection.id == newest_selection_id {
24003                            Some(
24004                                (range.start.0 as isize - selection.head().0 as isize)
24005                                    ..(range.end.0 as isize - selection.head().0 as isize),
24006                            )
24007                        } else {
24008                            None
24009                        }
24010                    })
24011            });
24012
24013            cx.emit(EditorEvent::InputHandled {
24014                utf16_range_to_replace: range_to_replace,
24015                text: text.into(),
24016            });
24017
24018            if let Some(new_selected_ranges) = new_selected_ranges {
24019                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24020                    selections.select_ranges(new_selected_ranges)
24021                });
24022                this.backspace(&Default::default(), window, cx);
24023            }
24024
24025            this.handle_input(text, window, cx);
24026        });
24027
24028        if let Some(transaction) = self.ime_transaction {
24029            self.buffer.update(cx, |buffer, cx| {
24030                buffer.group_until_transaction(transaction, cx);
24031            });
24032        }
24033
24034        self.unmark_text(window, cx);
24035    }
24036
24037    fn replace_and_mark_text_in_range(
24038        &mut self,
24039        range_utf16: Option<Range<usize>>,
24040        text: &str,
24041        new_selected_range_utf16: Option<Range<usize>>,
24042        window: &mut Window,
24043        cx: &mut Context<Self>,
24044    ) {
24045        if !self.input_enabled {
24046            return;
24047        }
24048
24049        let transaction = self.transact(window, cx, |this, window, cx| {
24050            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24051                let snapshot = this.buffer.read(cx).read(cx);
24052                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24053                    for marked_range in &mut marked_ranges {
24054                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24055                        marked_range.start.0 += relative_range_utf16.start;
24056                        marked_range.start =
24057                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24058                        marked_range.end =
24059                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24060                    }
24061                }
24062                Some(marked_ranges)
24063            } else if let Some(range_utf16) = range_utf16 {
24064                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24065                Some(this.selection_replacement_ranges(range_utf16, cx))
24066            } else {
24067                None
24068            };
24069
24070            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24071                let newest_selection_id = this.selections.newest_anchor().id;
24072                this.selections
24073                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24074                    .iter()
24075                    .zip(ranges_to_replace.iter())
24076                    .find_map(|(selection, range)| {
24077                        if selection.id == newest_selection_id {
24078                            Some(
24079                                (range.start.0 as isize - selection.head().0 as isize)
24080                                    ..(range.end.0 as isize - selection.head().0 as isize),
24081                            )
24082                        } else {
24083                            None
24084                        }
24085                    })
24086            });
24087
24088            cx.emit(EditorEvent::InputHandled {
24089                utf16_range_to_replace: range_to_replace,
24090                text: text.into(),
24091            });
24092
24093            if let Some(ranges) = ranges_to_replace {
24094                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24095                    s.select_ranges(ranges)
24096                });
24097            }
24098
24099            let marked_ranges = {
24100                let snapshot = this.buffer.read(cx).read(cx);
24101                this.selections
24102                    .disjoint_anchors_arc()
24103                    .iter()
24104                    .map(|selection| {
24105                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24106                    })
24107                    .collect::<Vec<_>>()
24108            };
24109
24110            if text.is_empty() {
24111                this.unmark_text(window, cx);
24112            } else {
24113                this.highlight_text::<InputComposition>(
24114                    marked_ranges.clone(),
24115                    HighlightStyle {
24116                        underline: Some(UnderlineStyle {
24117                            thickness: px(1.),
24118                            color: None,
24119                            wavy: false,
24120                        }),
24121                        ..Default::default()
24122                    },
24123                    cx,
24124                );
24125            }
24126
24127            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24128            let use_autoclose = this.use_autoclose;
24129            let use_auto_surround = this.use_auto_surround;
24130            this.set_use_autoclose(false);
24131            this.set_use_auto_surround(false);
24132            this.handle_input(text, window, cx);
24133            this.set_use_autoclose(use_autoclose);
24134            this.set_use_auto_surround(use_auto_surround);
24135
24136            if let Some(new_selected_range) = new_selected_range_utf16 {
24137                let snapshot = this.buffer.read(cx).read(cx);
24138                let new_selected_ranges = marked_ranges
24139                    .into_iter()
24140                    .map(|marked_range| {
24141                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24142                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24143                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24144                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24145                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24146                    })
24147                    .collect::<Vec<_>>();
24148
24149                drop(snapshot);
24150                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24151                    selections.select_ranges(new_selected_ranges)
24152                });
24153            }
24154        });
24155
24156        self.ime_transaction = self.ime_transaction.or(transaction);
24157        if let Some(transaction) = self.ime_transaction {
24158            self.buffer.update(cx, |buffer, cx| {
24159                buffer.group_until_transaction(transaction, cx);
24160            });
24161        }
24162
24163        if self.text_highlights::<InputComposition>(cx).is_none() {
24164            self.ime_transaction.take();
24165        }
24166    }
24167
24168    fn bounds_for_range(
24169        &mut self,
24170        range_utf16: Range<usize>,
24171        element_bounds: gpui::Bounds<Pixels>,
24172        window: &mut Window,
24173        cx: &mut Context<Self>,
24174    ) -> Option<gpui::Bounds<Pixels>> {
24175        let text_layout_details = self.text_layout_details(window);
24176        let CharacterDimensions {
24177            em_width,
24178            em_advance,
24179            line_height,
24180        } = self.character_dimensions(window);
24181
24182        let snapshot = self.snapshot(window, cx);
24183        let scroll_position = snapshot.scroll_position();
24184        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24185
24186        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24187        let x = Pixels::from(
24188            ScrollOffset::from(
24189                snapshot.x_for_display_point(start, &text_layout_details)
24190                    + self.gutter_dimensions.full_width(),
24191            ) - scroll_left,
24192        );
24193        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24194
24195        Some(Bounds {
24196            origin: element_bounds.origin + point(x, y),
24197            size: size(em_width, line_height),
24198        })
24199    }
24200
24201    fn character_index_for_point(
24202        &mut self,
24203        point: gpui::Point<Pixels>,
24204        _window: &mut Window,
24205        _cx: &mut Context<Self>,
24206    ) -> Option<usize> {
24207        let position_map = self.last_position_map.as_ref()?;
24208        if !position_map.text_hitbox.contains(&point) {
24209            return None;
24210        }
24211        let display_point = position_map.point_for_position(point).previous_valid;
24212        let anchor = position_map
24213            .snapshot
24214            .display_point_to_anchor(display_point, Bias::Left);
24215        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24216        Some(utf16_offset.0)
24217    }
24218}
24219
24220trait SelectionExt {
24221    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24222    fn spanned_rows(
24223        &self,
24224        include_end_if_at_line_start: bool,
24225        map: &DisplaySnapshot,
24226    ) -> Range<MultiBufferRow>;
24227}
24228
24229impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24230    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24231        let start = self
24232            .start
24233            .to_point(map.buffer_snapshot())
24234            .to_display_point(map);
24235        let end = self
24236            .end
24237            .to_point(map.buffer_snapshot())
24238            .to_display_point(map);
24239        if self.reversed {
24240            end..start
24241        } else {
24242            start..end
24243        }
24244    }
24245
24246    fn spanned_rows(
24247        &self,
24248        include_end_if_at_line_start: bool,
24249        map: &DisplaySnapshot,
24250    ) -> Range<MultiBufferRow> {
24251        let start = self.start.to_point(map.buffer_snapshot());
24252        let mut end = self.end.to_point(map.buffer_snapshot());
24253        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24254            end.row -= 1;
24255        }
24256
24257        let buffer_start = map.prev_line_boundary(start).0;
24258        let buffer_end = map.next_line_boundary(end).0;
24259        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24260    }
24261}
24262
24263impl<T: InvalidationRegion> InvalidationStack<T> {
24264    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24265    where
24266        S: Clone + ToOffset,
24267    {
24268        while let Some(region) = self.last() {
24269            let all_selections_inside_invalidation_ranges =
24270                if selections.len() == region.ranges().len() {
24271                    selections
24272                        .iter()
24273                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24274                        .all(|(selection, invalidation_range)| {
24275                            let head = selection.head().to_offset(buffer);
24276                            invalidation_range.start <= head && invalidation_range.end >= head
24277                        })
24278                } else {
24279                    false
24280                };
24281
24282            if all_selections_inside_invalidation_ranges {
24283                break;
24284            } else {
24285                self.pop();
24286            }
24287        }
24288    }
24289}
24290
24291impl<T> Default for InvalidationStack<T> {
24292    fn default() -> Self {
24293        Self(Default::default())
24294    }
24295}
24296
24297impl<T> Deref for InvalidationStack<T> {
24298    type Target = Vec<T>;
24299
24300    fn deref(&self) -> &Self::Target {
24301        &self.0
24302    }
24303}
24304
24305impl<T> DerefMut for InvalidationStack<T> {
24306    fn deref_mut(&mut self) -> &mut Self::Target {
24307        &mut self.0
24308    }
24309}
24310
24311impl InvalidationRegion for SnippetState {
24312    fn ranges(&self) -> &[Range<Anchor>] {
24313        &self.ranges[self.active_index]
24314    }
24315}
24316
24317fn edit_prediction_edit_text(
24318    current_snapshot: &BufferSnapshot,
24319    edits: &[(Range<Anchor>, String)],
24320    edit_preview: &EditPreview,
24321    include_deletions: bool,
24322    cx: &App,
24323) -> HighlightedText {
24324    let edits = edits
24325        .iter()
24326        .map(|(anchor, text)| {
24327            (
24328                anchor.start.text_anchor..anchor.end.text_anchor,
24329                text.clone(),
24330            )
24331        })
24332        .collect::<Vec<_>>();
24333
24334    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24335}
24336
24337fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24338    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24339    // Just show the raw edit text with basic styling
24340    let mut text = String::new();
24341    let mut highlights = Vec::new();
24342
24343    let insertion_highlight_style = HighlightStyle {
24344        color: Some(cx.theme().colors().text),
24345        ..Default::default()
24346    };
24347
24348    for (_, edit_text) in edits {
24349        let start_offset = text.len();
24350        text.push_str(edit_text);
24351        let end_offset = text.len();
24352
24353        if start_offset < end_offset {
24354            highlights.push((start_offset..end_offset, insertion_highlight_style));
24355        }
24356    }
24357
24358    HighlightedText {
24359        text: text.into(),
24360        highlights,
24361    }
24362}
24363
24364pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24365    match severity {
24366        lsp::DiagnosticSeverity::ERROR => colors.error,
24367        lsp::DiagnosticSeverity::WARNING => colors.warning,
24368        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24369        lsp::DiagnosticSeverity::HINT => colors.info,
24370        _ => colors.ignored,
24371    }
24372}
24373
24374pub fn styled_runs_for_code_label<'a>(
24375    label: &'a CodeLabel,
24376    syntax_theme: &'a theme::SyntaxTheme,
24377) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24378    let fade_out = HighlightStyle {
24379        fade_out: Some(0.35),
24380        ..Default::default()
24381    };
24382
24383    let mut prev_end = label.filter_range.end;
24384    label
24385        .runs
24386        .iter()
24387        .enumerate()
24388        .flat_map(move |(ix, (range, highlight_id))| {
24389            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24390                style
24391            } else {
24392                return Default::default();
24393            };
24394            let muted_style = style.highlight(fade_out);
24395
24396            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24397            if range.start >= label.filter_range.end {
24398                if range.start > prev_end {
24399                    runs.push((prev_end..range.start, fade_out));
24400                }
24401                runs.push((range.clone(), muted_style));
24402            } else if range.end <= label.filter_range.end {
24403                runs.push((range.clone(), style));
24404            } else {
24405                runs.push((range.start..label.filter_range.end, style));
24406                runs.push((label.filter_range.end..range.end, muted_style));
24407            }
24408            prev_end = cmp::max(prev_end, range.end);
24409
24410            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24411                runs.push((prev_end..label.text.len(), fade_out));
24412            }
24413
24414            runs
24415        })
24416}
24417
24418pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24419    let mut prev_index = 0;
24420    let mut prev_codepoint: Option<char> = None;
24421    text.char_indices()
24422        .chain([(text.len(), '\0')])
24423        .filter_map(move |(index, codepoint)| {
24424            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24425            let is_boundary = index == text.len()
24426                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24427                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24428            if is_boundary {
24429                let chunk = &text[prev_index..index];
24430                prev_index = index;
24431                Some(chunk)
24432            } else {
24433                None
24434            }
24435        })
24436}
24437
24438pub trait RangeToAnchorExt: Sized {
24439    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24440
24441    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24442        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24443        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24444    }
24445}
24446
24447impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24448    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24449        let start_offset = self.start.to_offset(snapshot);
24450        let end_offset = self.end.to_offset(snapshot);
24451        if start_offset == end_offset {
24452            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24453        } else {
24454            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24455        }
24456    }
24457}
24458
24459pub trait RowExt {
24460    fn as_f64(&self) -> f64;
24461
24462    fn next_row(&self) -> Self;
24463
24464    fn previous_row(&self) -> Self;
24465
24466    fn minus(&self, other: Self) -> u32;
24467}
24468
24469impl RowExt for DisplayRow {
24470    fn as_f64(&self) -> f64 {
24471        self.0 as _
24472    }
24473
24474    fn next_row(&self) -> Self {
24475        Self(self.0 + 1)
24476    }
24477
24478    fn previous_row(&self) -> Self {
24479        Self(self.0.saturating_sub(1))
24480    }
24481
24482    fn minus(&self, other: Self) -> u32 {
24483        self.0 - other.0
24484    }
24485}
24486
24487impl RowExt for MultiBufferRow {
24488    fn as_f64(&self) -> f64 {
24489        self.0 as _
24490    }
24491
24492    fn next_row(&self) -> Self {
24493        Self(self.0 + 1)
24494    }
24495
24496    fn previous_row(&self) -> Self {
24497        Self(self.0.saturating_sub(1))
24498    }
24499
24500    fn minus(&self, other: Self) -> u32 {
24501        self.0 - other.0
24502    }
24503}
24504
24505trait RowRangeExt {
24506    type Row;
24507
24508    fn len(&self) -> usize;
24509
24510    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24511}
24512
24513impl RowRangeExt for Range<MultiBufferRow> {
24514    type Row = MultiBufferRow;
24515
24516    fn len(&self) -> usize {
24517        (self.end.0 - self.start.0) as usize
24518    }
24519
24520    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24521        (self.start.0..self.end.0).map(MultiBufferRow)
24522    }
24523}
24524
24525impl RowRangeExt for Range<DisplayRow> {
24526    type Row = DisplayRow;
24527
24528    fn len(&self) -> usize {
24529        (self.end.0 - self.start.0) as usize
24530    }
24531
24532    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24533        (self.start.0..self.end.0).map(DisplayRow)
24534    }
24535}
24536
24537/// If select range has more than one line, we
24538/// just point the cursor to range.start.
24539fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24540    if range.start.row == range.end.row {
24541        range
24542    } else {
24543        range.start..range.start
24544    }
24545}
24546pub struct KillRing(ClipboardItem);
24547impl Global for KillRing {}
24548
24549const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24550
24551enum BreakpointPromptEditAction {
24552    Log,
24553    Condition,
24554    HitCondition,
24555}
24556
24557struct BreakpointPromptEditor {
24558    pub(crate) prompt: Entity<Editor>,
24559    editor: WeakEntity<Editor>,
24560    breakpoint_anchor: Anchor,
24561    breakpoint: Breakpoint,
24562    edit_action: BreakpointPromptEditAction,
24563    block_ids: HashSet<CustomBlockId>,
24564    editor_margins: Arc<Mutex<EditorMargins>>,
24565    _subscriptions: Vec<Subscription>,
24566}
24567
24568impl BreakpointPromptEditor {
24569    const MAX_LINES: u8 = 4;
24570
24571    fn new(
24572        editor: WeakEntity<Editor>,
24573        breakpoint_anchor: Anchor,
24574        breakpoint: Breakpoint,
24575        edit_action: BreakpointPromptEditAction,
24576        window: &mut Window,
24577        cx: &mut Context<Self>,
24578    ) -> Self {
24579        let base_text = match edit_action {
24580            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24581            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24582            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24583        }
24584        .map(|msg| msg.to_string())
24585        .unwrap_or_default();
24586
24587        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24588        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24589
24590        let prompt = cx.new(|cx| {
24591            let mut prompt = Editor::new(
24592                EditorMode::AutoHeight {
24593                    min_lines: 1,
24594                    max_lines: Some(Self::MAX_LINES as usize),
24595                },
24596                buffer,
24597                None,
24598                window,
24599                cx,
24600            );
24601            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24602            prompt.set_show_cursor_when_unfocused(false, cx);
24603            prompt.set_placeholder_text(
24604                match edit_action {
24605                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24606                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24607                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24608                },
24609                window,
24610                cx,
24611            );
24612
24613            prompt
24614        });
24615
24616        Self {
24617            prompt,
24618            editor,
24619            breakpoint_anchor,
24620            breakpoint,
24621            edit_action,
24622            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24623            block_ids: Default::default(),
24624            _subscriptions: vec![],
24625        }
24626    }
24627
24628    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24629        self.block_ids.extend(block_ids)
24630    }
24631
24632    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24633        if let Some(editor) = self.editor.upgrade() {
24634            let message = self
24635                .prompt
24636                .read(cx)
24637                .buffer
24638                .read(cx)
24639                .as_singleton()
24640                .expect("A multi buffer in breakpoint prompt isn't possible")
24641                .read(cx)
24642                .as_rope()
24643                .to_string();
24644
24645            editor.update(cx, |editor, cx| {
24646                editor.edit_breakpoint_at_anchor(
24647                    self.breakpoint_anchor,
24648                    self.breakpoint.clone(),
24649                    match self.edit_action {
24650                        BreakpointPromptEditAction::Log => {
24651                            BreakpointEditAction::EditLogMessage(message.into())
24652                        }
24653                        BreakpointPromptEditAction::Condition => {
24654                            BreakpointEditAction::EditCondition(message.into())
24655                        }
24656                        BreakpointPromptEditAction::HitCondition => {
24657                            BreakpointEditAction::EditHitCondition(message.into())
24658                        }
24659                    },
24660                    cx,
24661                );
24662
24663                editor.remove_blocks(self.block_ids.clone(), None, cx);
24664                cx.focus_self(window);
24665            });
24666        }
24667    }
24668
24669    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24670        self.editor
24671            .update(cx, |editor, cx| {
24672                editor.remove_blocks(self.block_ids.clone(), None, cx);
24673                window.focus(&editor.focus_handle);
24674            })
24675            .log_err();
24676    }
24677
24678    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24679        let settings = ThemeSettings::get_global(cx);
24680        let text_style = TextStyle {
24681            color: if self.prompt.read(cx).read_only(cx) {
24682                cx.theme().colors().text_disabled
24683            } else {
24684                cx.theme().colors().text
24685            },
24686            font_family: settings.buffer_font.family.clone(),
24687            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24688            font_size: settings.buffer_font_size(cx).into(),
24689            font_weight: settings.buffer_font.weight,
24690            line_height: relative(settings.buffer_line_height.value()),
24691            ..Default::default()
24692        };
24693        EditorElement::new(
24694            &self.prompt,
24695            EditorStyle {
24696                background: cx.theme().colors().editor_background,
24697                local_player: cx.theme().players().local(),
24698                text: text_style,
24699                ..Default::default()
24700            },
24701        )
24702    }
24703}
24704
24705impl Render for BreakpointPromptEditor {
24706    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24707        let editor_margins = *self.editor_margins.lock();
24708        let gutter_dimensions = editor_margins.gutter;
24709        h_flex()
24710            .key_context("Editor")
24711            .bg(cx.theme().colors().editor_background)
24712            .border_y_1()
24713            .border_color(cx.theme().status().info_border)
24714            .size_full()
24715            .py(window.line_height() / 2.5)
24716            .on_action(cx.listener(Self::confirm))
24717            .on_action(cx.listener(Self::cancel))
24718            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24719            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24720    }
24721}
24722
24723impl Focusable for BreakpointPromptEditor {
24724    fn focus_handle(&self, cx: &App) -> FocusHandle {
24725        self.prompt.focus_handle(cx)
24726    }
24727}
24728
24729fn all_edits_insertions_or_deletions(
24730    edits: &Vec<(Range<Anchor>, String)>,
24731    snapshot: &MultiBufferSnapshot,
24732) -> bool {
24733    let mut all_insertions = true;
24734    let mut all_deletions = true;
24735
24736    for (range, new_text) in edits.iter() {
24737        let range_is_empty = range.to_offset(snapshot).is_empty();
24738        let text_is_empty = new_text.is_empty();
24739
24740        if range_is_empty != text_is_empty {
24741            if range_is_empty {
24742                all_deletions = false;
24743            } else {
24744                all_insertions = false;
24745            }
24746        } else {
24747            return false;
24748        }
24749
24750        if !all_insertions && !all_deletions {
24751            return false;
24752        }
24753    }
24754    all_insertions || all_deletions
24755}
24756
24757struct MissingEditPredictionKeybindingTooltip;
24758
24759impl Render for MissingEditPredictionKeybindingTooltip {
24760    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24761        ui::tooltip_container(cx, |container, cx| {
24762            container
24763                .flex_shrink_0()
24764                .max_w_80()
24765                .min_h(rems_from_px(124.))
24766                .justify_between()
24767                .child(
24768                    v_flex()
24769                        .flex_1()
24770                        .text_ui_sm(cx)
24771                        .child(Label::new("Conflict with Accept Keybinding"))
24772                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24773                )
24774                .child(
24775                    h_flex()
24776                        .pb_1()
24777                        .gap_1()
24778                        .items_end()
24779                        .w_full()
24780                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24781                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24782                        }))
24783                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24784                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24785                        })),
24786                )
24787        })
24788    }
24789}
24790
24791#[derive(Debug, Clone, Copy, PartialEq)]
24792pub struct LineHighlight {
24793    pub background: Background,
24794    pub border: Option<gpui::Hsla>,
24795    pub include_gutter: bool,
24796    pub type_id: Option<TypeId>,
24797}
24798
24799struct LineManipulationResult {
24800    pub new_text: String,
24801    pub line_count_before: usize,
24802    pub line_count_after: usize,
24803}
24804
24805fn render_diff_hunk_controls(
24806    row: u32,
24807    status: &DiffHunkStatus,
24808    hunk_range: Range<Anchor>,
24809    is_created_file: bool,
24810    line_height: Pixels,
24811    editor: &Entity<Editor>,
24812    _window: &mut Window,
24813    cx: &mut App,
24814) -> AnyElement {
24815    h_flex()
24816        .h(line_height)
24817        .mr_1()
24818        .gap_1()
24819        .px_0p5()
24820        .pb_1()
24821        .border_x_1()
24822        .border_b_1()
24823        .border_color(cx.theme().colors().border_variant)
24824        .rounded_b_lg()
24825        .bg(cx.theme().colors().editor_background)
24826        .gap_1()
24827        .block_mouse_except_scroll()
24828        .shadow_md()
24829        .child(if status.has_secondary_hunk() {
24830            Button::new(("stage", row as u64), "Stage")
24831                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24832                .tooltip({
24833                    let focus_handle = editor.focus_handle(cx);
24834                    move |window, cx| {
24835                        Tooltip::for_action_in(
24836                            "Stage Hunk",
24837                            &::git::ToggleStaged,
24838                            &focus_handle,
24839                            window,
24840                            cx,
24841                        )
24842                    }
24843                })
24844                .on_click({
24845                    let editor = editor.clone();
24846                    move |_event, _window, cx| {
24847                        editor.update(cx, |editor, cx| {
24848                            editor.stage_or_unstage_diff_hunks(
24849                                true,
24850                                vec![hunk_range.start..hunk_range.start],
24851                                cx,
24852                            );
24853                        });
24854                    }
24855                })
24856        } else {
24857            Button::new(("unstage", row as u64), "Unstage")
24858                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24859                .tooltip({
24860                    let focus_handle = editor.focus_handle(cx);
24861                    move |window, cx| {
24862                        Tooltip::for_action_in(
24863                            "Unstage Hunk",
24864                            &::git::ToggleStaged,
24865                            &focus_handle,
24866                            window,
24867                            cx,
24868                        )
24869                    }
24870                })
24871                .on_click({
24872                    let editor = editor.clone();
24873                    move |_event, _window, cx| {
24874                        editor.update(cx, |editor, cx| {
24875                            editor.stage_or_unstage_diff_hunks(
24876                                false,
24877                                vec![hunk_range.start..hunk_range.start],
24878                                cx,
24879                            );
24880                        });
24881                    }
24882                })
24883        })
24884        .child(
24885            Button::new(("restore", row as u64), "Restore")
24886                .tooltip({
24887                    let focus_handle = editor.focus_handle(cx);
24888                    move |window, cx| {
24889                        Tooltip::for_action_in(
24890                            "Restore Hunk",
24891                            &::git::Restore,
24892                            &focus_handle,
24893                            window,
24894                            cx,
24895                        )
24896                    }
24897                })
24898                .on_click({
24899                    let editor = editor.clone();
24900                    move |_event, window, cx| {
24901                        editor.update(cx, |editor, cx| {
24902                            let snapshot = editor.snapshot(window, cx);
24903                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24904                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24905                        });
24906                    }
24907                })
24908                .disabled(is_created_file),
24909        )
24910        .when(
24911            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24912            |el| {
24913                el.child(
24914                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24915                        .shape(IconButtonShape::Square)
24916                        .icon_size(IconSize::Small)
24917                        // .disabled(!has_multiple_hunks)
24918                        .tooltip({
24919                            let focus_handle = editor.focus_handle(cx);
24920                            move |window, cx| {
24921                                Tooltip::for_action_in(
24922                                    "Next Hunk",
24923                                    &GoToHunk,
24924                                    &focus_handle,
24925                                    window,
24926                                    cx,
24927                                )
24928                            }
24929                        })
24930                        .on_click({
24931                            let editor = editor.clone();
24932                            move |_event, window, cx| {
24933                                editor.update(cx, |editor, cx| {
24934                                    let snapshot = editor.snapshot(window, cx);
24935                                    let position =
24936                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24937                                    editor.go_to_hunk_before_or_after_position(
24938                                        &snapshot,
24939                                        position,
24940                                        Direction::Next,
24941                                        window,
24942                                        cx,
24943                                    );
24944                                    editor.expand_selected_diff_hunks(cx);
24945                                });
24946                            }
24947                        }),
24948                )
24949                .child(
24950                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24951                        .shape(IconButtonShape::Square)
24952                        .icon_size(IconSize::Small)
24953                        // .disabled(!has_multiple_hunks)
24954                        .tooltip({
24955                            let focus_handle = editor.focus_handle(cx);
24956                            move |window, cx| {
24957                                Tooltip::for_action_in(
24958                                    "Previous Hunk",
24959                                    &GoToPreviousHunk,
24960                                    &focus_handle,
24961                                    window,
24962                                    cx,
24963                                )
24964                            }
24965                        })
24966                        .on_click({
24967                            let editor = editor.clone();
24968                            move |_event, window, cx| {
24969                                editor.update(cx, |editor, cx| {
24970                                    let snapshot = editor.snapshot(window, cx);
24971                                    let point =
24972                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24973                                    editor.go_to_hunk_before_or_after_position(
24974                                        &snapshot,
24975                                        point,
24976                                        Direction::Prev,
24977                                        window,
24978                                        cx,
24979                                    );
24980                                    editor.expand_selected_diff_hunks(cx);
24981                                });
24982                            }
24983                        }),
24984                )
24985            },
24986        )
24987        .into_any_element()
24988}
24989
24990pub fn multibuffer_context_lines(cx: &App) -> u32 {
24991    EditorSettings::try_get(cx)
24992        .map(|settings| settings.excerpt_context_lines)
24993        .unwrap_or(2)
24994        .min(32)
24995}